[opensuse] BASH gurus - are continuations broken?
Listmates, I cannot figure out the differences that the continuations are making in the following lines of code. It looks like bash isn't handling the continuations correctly. The block of code doesn't work, the identical one-liner does. Here is the code: BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' \ -e 's/^\s*//' -e 's/\s*$//' \ -e 's/ /_/g' -e 's/__/_/g' \ -e 's/_-_*/-/g') BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' -e 's/^\s*//' -e 's/\s*$//' -e 's/ /_/g' -e 's/__/_/g' -e 's/_-_*/-/g') What say the gurus? -- David C. Rankin, J.D., P.E. Rankin Law Firm, PLLC 510 Ochiltree Street Nacogdoches, Texas 75961 Telephone: (936) 715-9333 Facsimile: (936) 715-9339 www.rankinlawfirm.com -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Saturday 16 August 2008 19:13:15 David C. Rankin wrote:
Listmates,
I cannot figure out the differences that the continuations are making in the following lines of code. It looks like bash isn't handling the continuations correctly. The block of code doesn't work, the identical one-liner does. Here is the code:
BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' \ -e 's/^\s*//' -e 's/\s*$//' \ -e 's/ /_/g' -e 's/__/_/g' \ -e 's/_-_*/-/g')
BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' -e 's/^\s*//' -e 's/\s*$//' -e 's/ /_/g' -e 's/__/_/g' -e 's/_-_*/-/g')
What say the gurus?
You want to enclose the $1 in quotes if you want it to be able to handle files with spaces in their names, other than that, both versions work fine for me Anders -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
Anders Johansson wrote:
On Saturday 16 August 2008 19:13:15 David C. Rankin wrote:
Listmates,
I cannot figure out the differences that the continuations are making in the following lines of code. It looks like bash isn't handling the continuations correctly. The block of code doesn't work, the identical one-liner does. Here is the code:
BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' \ -e 's/^\s*//' -e 's/\s*$//' \ -e 's/ /_/g' -e 's/__/_/g' \ -e 's/_-_*/-/g')
BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' -e 's/^\s*//' -e 's/\s*$//' -e 's/ /_/g' -e 's/__/_/g' -e 's/_-_*/-/g')
What say the gurus?
You want to enclose the $1 in quotes if you want it to be able to handle files with spaces in their names, other than that, both versions work fine for me
Anders
Anders, I don't really know what the problem was either. This is in what is really a two-part script called using the -exec option to find. I didn't quote it for expansion because I though I was handling that both with the -print0 option of find and by changing IFS=$'\n' in the script prior to the basename call. I did however find some whitespace after one of the continuations. It was a tab character from when I attempted to have inline comments after each line. (a no-no since it was within the BASENAME=$( )) block. I removed the tab character and it now works as it is supposed to both quoted and not. Even feeding it some fairly ugly filenames: -rw-r--r-- 1 david dcr 23 2008-08-19 01:21 " this is a - good test.JPG " Thanks for your feedback and help. -- David C. Rankin, J.D., P.E. Rankin Law Firm, PLLC 510 Ochiltree Street Nacogdoches, Texas 75961 Telephone: (936) 715-9333 Facsimile: (936) 715-9339 www.rankinlawfirm.com -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
----- Original Message -----
From: "David C. Rankin"
Listmates,
I cannot figure out the differences that the continuations are making in the following lines of code. It looks like bash isn't handling the continuations correctly. The block of code doesn't work, the identical one-liner does. Here is the code:
BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' \ -e 's/^\s*//' -e 's/\s*$//' \ -e 's/ /_/g' -e 's/__/_/g' \ -e 's/_-_*/-/g')
BASENAME=$(echo $(basename $1 .JPG) | sed -e 's/\"//g' -e 's/^\s*//' -e 's/\s*$//' -e 's/ /_/g' -e 's/__/_/g' -e 's/_-_*/-/g')
What say the gurus?
What you have works fine. But, you don't need line continuation for this. Mostly for readability & maintainability and a little more thoroughness I'd do this: A=`echo "$1" |sed ' s;.*/;; s;[\"\$\&\;\*\{\}\(\)\<\>\\];;g s;\s;_;g s;^_*;; s;_*$;; s;__*;_;g s;-_;-;g s;_-;-;g s;--*;-;g s;^-;; s;\.[Jj][Pp][Gg]$;; s;[-_]$;; '` 1 strip leading path 2 strip quotes and other shell-active characters 3 convert any kind of whitespace to _ 4 strip leading _ 5 strip trailing _ 6 collapse any number of _ to one _ 7 -_ to - 8 _- to - 9 collapse any number of - to one - 10 strip leading - No * needed, there will only ever be one or none because of line 9 11 strip trailing .jpg, case insensative 12 strip trailing - or _ After stripping the extension, a formerly embedded - or _ might now be a trailing one. By this point all - and _ and combos should have been collapsed into a single - or _, so no * sould be needed. Basename replaced by lines 1 & 11 which gets rid of spawning 2 processes. .../g doesn't always make sense. For example, there is only one instance of "from here to end of line" on any given line. Order of most of the ops above matters. That handles a lot more cases than originally. Could have been done other ways too, but starting by converting all whitespace to _ makes the subsequent commands a little simpler and shorter as long as you were going to do that eventually anyways. Line 2 strips a lot more than just quotes. Maybe more than you'd like. If you are not planning on always being very careful in your handling of these filenames, always quoting the strings every time & place they are referenced or handled, then there is not much point in stripping out the spaces & quotes if you are not also going to deal with everything else that might be active on a shell command line. ";" is far more dangerous than space. escape and other control bytes are bad too though more cosmetic than dangerous. If you want to only strip quotes then line 2 only needs to be: s;\";;g If you are always going to handle the strings with care, then you can delete line 2 altogether. Leaving in the spaces & other stuff is not evil in this case because these are files that are handled by non-techy users in environments where it's OK. They don't know or care about unix file name and shell expansion considerations and why should they? Your Aunt wants "Julia & Mark's birthday!!.jpg" and I say for that kind of thing it's better to actually allow it and keep the special rules and limitations to a minimum. You, as a unix user, of course know that simple filenames are handy sometimes, but by the same token, you, as a unix user, can also be expected to simply know they ways to deal with filenames that may contain characters that may be meaningful to your shell command line. IE, you quote them. And/or you access them only from similarly safe environments yourself where no special care is needed. (graphics programs, gui file browsers, midnight commander, etc) Most programs that weren't written in crayon can handle filenames with any characters that are allowed by the filesystem. If you have say, a backup program, that chokes on _any_ filename that the filesystem even allows to exist, then don't use that backup program. Also, just as a neat example, if you trusted your filenames not to have shell active characters in them, or if you were willing to simply strip or convert any that might be in there with a few more "A=" inserted between line 1 & 2 below, then you actually don't need sed at all. A=${1//\"/} # strip quotes A=${A//_/ } # _ to " " A=`echo ${A##*/}` # strip leading path and all extra whitespace A=${A// /_} # " " to _ A=${A//_-_/-} # _-_ to - A=${A%.JPG} # strip trailing .JPG no sed, no basename, only one spawned shell line 3 the ${A##*/} syntax strips the leading path then the echo command, or rather the shell command line parser, strips the leading and trailing whitespace and collapses all embedded whitespace. -- Brian K. White brian@aljex.com http://www.myspace.com/KEYofR +++++[>+++[>+++++>+++++++<<-]<-]>>+.>.+++++.+++++++.-.[>+<---]>++. filePro BBx Linux SCO FreeBSD #callahans Satriani Filk! -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Sun, 17 Aug 2008, Brian K. White wrote:- <snip>
A=${1//\"/} # strip quotes A=${A//_/ } # _ to " " A=`echo ${A##*/}` # strip leading path and all extra whitespace A=${A// /_} # " " to _ A=${A//_-_/-} # _-_ to - A=${A%.JPG} # strip trailing .JPG
no sed, no basename, only one spawned shell line 3 the ${A##*/} syntax strips the leading path then the echo command, or rather the shell command line parser, strips the leading and trailing whitespace and collapses all embedded whitespace.
That doesn't work here: davjam@viper-mk2:~> i=" /test/test/tst " davjam@viper-mk2:~> echo "'${i##*/}'" 'tst ' davjam@viper-mk2:~> j=$(echo "${i##*/}") ; echo "'${j}'" 'tst ' This strips off the extra white spaces, but uses two shells: davjam@viper-mk2:~> j=$(echo "${i##*/}"|sed -r -e 's#^ +##' -e 's# +$##' ) ; echo "'${j}'" 'tst' Regards, David Bolt -- Team Acorn: http://www.distributed.net/ OGR-P2 @ ~100Mnodes RC5-72 @ ~15Mkeys SUSE 10.1 32 | | openSUSE 10.3 32b | openSUSE 11.0 32b | openSUSE 10.2 64b | openSUSE 10.3 64b | openSUSE 11.0 64b RISC OS 3.6 | TOS 4.02 | openSUSE 10.3 PPC | RISC OS 3.11 -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
----- Original Message -----
From: "David Bolt"
On Sun, 17 Aug 2008, Brian K. White wrote:-
<snip>
A=${1//\"/} # strip quotes A=${A//_/ } # _ to " " A=`echo ${A##*/}` # strip leading path and all extra whitespace A=${A// /_} # " " to _ A=${A//_-_/-} # _-_ to - A=${A%.JPG} # strip trailing .JPG
no sed, no basename, only one spawned shell line 3 the ${A##*/} syntax strips the leading path then the echo command, or rather the shell command line parser, strips the leading and trailing whitespace and collapses all embedded whitespace.
That doesn't work here:
davjam@viper-mk2:~> i=" /test/test/tst " davjam@viper-mk2:~> echo "'${i##*/}'" 'tst ' davjam@viper-mk2:~> j=$(echo "${i##*/}") ; echo "'${j}'" 'tst '
The commands I posted work exactly as advertized. What failed was your reading or performing them, since you did not execute the commands I posted. cairo $ i=" /test/test/tst " cairo $ A=${i//\"/} cairo $ A=${A//_/ } cairo $ A=`echo ${A##*/}` cairo $ A=${A// /_} cairo $ A=${A//_-_/-} cairo $ A=${A%.JPG} cairo $ echo "\"$A\"" "tst" I tested it with far more hideous path and file names that this too.
This strips off the extra white spaces, but uses two shells:
davjam@viper-mk2:~> j=$(echo "${i##*/}"|sed -r -e 's#^ +##' -e 's# +$##' ) ; echo "'${j}'" 'tst'
Unnecessary. -- Brian K. White brian@aljex.com http://www.myspace.com/KEYofR +++++[>+++[>+++++>+++++++<<-]<-]>>+.>.+++++.+++++++.-.[>+<---]>++. filePro BBx Linux SCO FreeBSD #callahans Satriani Filk! -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Sun, 17 Aug 2008, Brian K. White wrote:-
davjam@viper-mk2:~> j=$(echo "${i##*/}") ; echo "'${j}'" 'tst '
cairo $ A=`echo ${A##*/}`
I spotted the difference. As is my habit, I wrapped the ${i##*/} in quotes whereas you didn't, and so mine preserved the white space where yours didn't. So, yes yours would work. Regards, David Bolt -- Team Acorn: http://www.distributed.net/ OGR-P2 @ ~100Mnodes RC5-72 @ ~15Mkeys SUSE 10.1 32 | | openSUSE 10.3 32b | openSUSE 11.0 32b | openSUSE 10.2 64b | openSUSE 10.3 64b | openSUSE 11.0 64b RISC OS 3.6 | TOS 4.02 | openSUSE 10.3 PPC | RISC OS 3.11 -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
participants (4)
-
Anders Johansson
-
Brian K. White
-
David Bolt
-
David C. Rankin