braces and quotes 

Newsgroups:  comp.unix.shell
Date:        Mon, 30 Oct 2006 07:47:22 -0500
> I was reviewing the Suse/Gentoo run-crons script, and comparing it with
> some elementary scripts I had written. All of a sudden, I realized that
> despite reading the docs and advanced scripting manual, I really did not
> have a good grasp on the concept of when to quote, enclose in a brace, etc.
>
> This snippet crystallizes my confusion. ... For that matter, when would
> the assignment to LOCKDIR have to be quoted? If there is a whitespace?
>
> LOCKDIR=/var/spool/cron/lastrun
> LOCKFILE=${LOCKDIR}/lock
>
> echo "braces no quotes $LOCKFILE"
>
> LOCKFILE="${LOCKDIR}"/lock
> echo "braces quote $LOCKFILE"
>
> LOCKFILE=$LOCKDIR/lock
> echo "no braces no quote $LOCKFILE"
>
> LOCKFILE="$LOCKDIR"/lock
> echo "no braces quote $LOCKFILE"

None of the above examples need the braces or quotes. But here are some examples where they're necessary:

LOCKFILE=${LOCKDIR}1/lock

Without the braces, it would look for a variable named LOCKDIR1.

LOCKFILE="$LOCKDIR/lock file with spaces"

Without the quotes, it would set the environment variable to $LOCKDIR/lock while trying to execute the command line "file with spaces".

STRINGWITHSPACES="foo     bar"
echo $STRINGWITHSPACES
echo "$STRINGWITHSPACES"

The first one loses the multiple spaces between the words.

However, you don't need it here:

OTHERSTRING=$STRINGWITHSPACES

because word splitting of the assignment portion of a command is done before variable expansion.

Barry Margolin

:quote in eval 

NOK 
eval cd \"`cat ~/.pfm/cwd | strh hm_ca`\"
++ cat /home/tong/.pfm/cwd
++ strh hm_ca
+ eval cd '"~/s/tdRaw/pan"'
++ cd '~/s/tdRaw/pan'
bash: cd: ~/s/tdRaw/pan: No such file or directory
OK 
eval cd `cat ~/.pfm/cwd | strh hm_ca`
++ cat /home/tong/.pfm/cwd
++ strh hm_ca
+ eval cd '~/s/tdRaw/pan'
++ cd /home/tong/s/tdRaw/pan

documented on: 2003.03.09 Sun

:quote execution result 

no quote 
$ sh -xc 'filesb=`ls -A`; echo $filesb | od -c'
++ ls -A
+ filesb=etc
usr
+ echo etc usr
+ od -c
0000000   e   t   c       u   s   r  \n
0000010
quote 
$ sh -xc 'filesb=`ls -A`; echo "$filesb" | od -c'
++ ls -A
+ filesb=etc
usr
+ echo 'etc
usr'
+ od -c
0000000   e   t   c  \n   u   s   r  \n
0000010

documented on: 2004.02.25 Wed

quote within $() 

Newsgroups:  comp.unix.shell
Date:        Sun, 16 Oct 2005 17:44:52 +0200
> How to quote within the "$()" in posix compatible shells?
>
> I tried all the following but none of them worked. I need the "$()"
> notation because it is actually part of my long expression that have more
> "$()" in it.
>
> fname='a b c'
> echo "$(basename $fname)"
> echo "$(basename '$fname')"
> echo "$(basename \"$fname\")"
> echo "$(basename ${fname})"

This is what I do in bash. I don't know the specifics of POSIX compliance.

echo "$(basename "$fname")"

Notice that the dquotes inside the $() do the right thing. I believe bash starts a recursive processing of the innards of $() in unquoted mode, but quotes the captured command output when pasting it into the echo command.

Enrique Perez-Terron

quote within $() 

fname='a  b c'
$ echo "$(basename "$fname")"
a  b c

documented on: 2005.10.16

cmd:eval, substitution of varible value 

! >How can I substitute one part of variable into anthor string?

! >I just can't make it work. See bellow: ! > ! >sh << eof ! >echo "" ! […] ! >echo "" ! ! When you use <<string, variables are interpolated while the here-document ! is being read by the original shell. So the "echo $x" and "echo $y" ! commands in your here-document are using whatever values $x and $y had in ! the original shell, not their values that are being assigned in the ! subshell. ! ! Try putting your commands in a separate shell script file, or use ! sh <<'eof' ! ! When you use <<'string', it indicates that the here-document should be read ! in as if everything were quoted, so no interpolation is done.

> changing your `sh' to `sh -x' will let you
> see exactly what is happening:
> cmd=echo $x | sed "s/xxx/yyy/"
> + echo $x | sed "s/xxx/yyy/"
> + eval x=$x | sed "s/xxx/yyy/"
> + sed s/xxx/yyy/
> x=---xxx---
> + echo ---xxx---
> ---xxx---
>
> the command substitution on the line with the eval, you will note,
> gets expanded before the eval happens, meaning all the eval sees as
> a command line to evaluate is "x=$x".  so what happens is that you
> assign x to itself, and then pipe the output of that (which is nothing)
> to the sed command.

FYI, the following code works:

sh -vx << 'eof'
echo "###"
x="---xxx---"
cmd='eval echo $x | sed "s/xxx/yyy/"'
x=`$cmd`
echo $x
echo "###"
eof
>>
cmd='eval echo $x | sed "s/xxx/yyy/"'
cmd=eval echo $x | sed "s/xxx/yyy/"
x=`$cmd`
+ eval echo $x | sed "s/xxx/yyy/"
+ + sedecho ---xxx---
 s/xxx/yyy/
x=---yyy---
echo $x
+ echo ---yyy---
>>

documented on: 1999.09.04 Sat 19:46:40

' in bash alias 

>I just can't make the following alias works:
>
>mytestalias='awk -F'"' ...'
alias myt="awk -F'\"' ..."

Can't escape single quotes in a single-quoted string.

Chet Ramey

' in bash alias 

>I've tried
>
>mytestalias=awk -F'"' ...

Word-split at the unquoted space; also would not have protected the " from its special meaning when the alias gets expanded. Try:

alias mytestalias=awk\ -F'\"'\ ...
>mytestalias='awk -F\'\"\' ...'

Backslashes are not special within single-quoted strings; could use:

alias mytestalias='awk -F\" ...'

Ken Pizzini

documented on: 1999.10.09 Sat 13:45:34

cmd:sqt/sdq string quote & dequote 

bash$ alias sqt='sed "s/'\''/'\''\\\\'\'''\''/g; s/^/'\''/; s/$/'\''/"'
bash$ alias sdq='echo '
bash$ sqt
sed "s/'/'\\\\''/g; s/^/'/; s/$/'/"
'sed "s/'\''/'\''\\\\'\'''\''/g; s/^/'\''/; s/$/'\''/"'
bash$ sdq 'sed "s/'\''/'\''\\\\'\'''\''/g; s/^/'\''/; s/$/'\''/"'
sed "s/'/'\\\\''/g; s/^/'/; s/$/'/"
bash$

documented on: 2000.06.06 Tue 12:04:40

quoting question 

> I know I can use
>
> xterm -e sh -c 'command;echo Type Control-d to close window;cat'
>
> to invoke a predefined command, Now, how to make it into a sh
> function so that I can use any arbitrary commands?
>
> I've tried to come up with the following, but none of them works:
>
> testit(){ xterm -e sh -c "'$@;echo Type Control-d to close window;cat'" & }
testit(){ xterm -e sh -c "$*;echo Type Control-d to close window;cat" & }

Manfred Bartz

X"$Y" vs. "X$Y" in /bin/sh 

*Tags*: cmd:case

Date: 1999-08-24
> > >  case "$VAR" in
> > Heck, with case you don't even need the quotes:
> >    case $VAR in
> >      YES) ... ;;
> >    esac
>
>  Hrrrmm... what if it's possible that the expansion will result in an
> empty string? Wouldn't quotes be the safe way to go "just in case?"

It is definitely safe to add them, but the case statement will still work correctly even if the variable does expand to an empty string:

    $ v=
    $ case $v in "") echo empty;; *) echo not empty ;; esac
    empty
    $ v=in
    $ case $v in "") echo empty;; *) echo not empty ;; esac
    not empty
    $ case $v in *\ *) echo has space ;; *) echo no space ;; esac
    no space
    $ v="foo bar"
    $ case $v in *\ *) echo has space ;; *) echo no space ;; esac
    has space
    $ v="foo*bar"
    $ case $v in *\**) echo has star ;; *) echo no star ;; esac
    has star

There is certainly nothing wrong with adding double-quotes around a variable expansion which is used as the word-to-be-cased in the case statement, I was merely pointing out that it is an additional benefit of using case (instead of test) that the quotes are not _required_.

Ken Pizzini

X"$Y" vs. "X$Y" in /bin/sh 

Variables are expanded for command execution. case is a keyword, while test "[ condition ]" is a builtin command. So in a test statement, variable expansion occurs. That is one of the reasons to use conditional expressions in ksh, the posix shell and bash: "[[" is a keyword, so variable and filename expansion do not occur.

For instance:

if [[ $VAR = xyz ]]

works for all values of $VAR. Note, it doesn't require quoting. However, the RHS may require quoting:

if [[ $VAR = "$xyz" ]]

And

if [[ $VAR = *xyz* ]]

is true if VAR contains the string or substring "xyz". If you tried that with test, *xyz* would expand to filenames containing the string xyz, or the literal pattern "*xyz*".

Dan Mercer