Re: () $() etc., in Bash
- From: Stephane CHAZELAS <this.address@xxxxxxxxxx>
- Date: Wed, 10 May 2006 09:01:51 +0100
2006-05-9, 18:49(-04), Chris F.A. Johnson:
On 2006-05-09, yusuf wrote:
what is $( ) ??
On 2006-05-09, Stephane CHAZELAS wrote:
2006-05-8, 13:48(-07), yusuf:
[...]
Also, would appreciate if someone could explain the different types and
usages in Bash for all the $(( .. )) , $[ ... ] etc.
$(...) is command substitution.
It is replaced on the command line by the output of the command
inside the parentheses.
That's a bit short, when unquoted and in list contexts, as in:
cmd -- $(cmd2)
or
for i in $(cmd2)
it is replaced on the command line by the result of the filename
generation (the process of expanding wildcard patterns into file
names) performed on the list of words that is obtained by
performing the word splitting (the process of taking a string
and chopping it into a list of words by a complex process
involving the $IFS special parameter and that is slightly
different from one shell to another) on the character string
that is the collected output of the command (as long as it
doesn't contain NUL characters) but where every trailing
linefeed character has been removed. (in zsh, the filename
generation is not performed).
In other words, if the cmd2 outputs:
" : *-* : bar baz:<LF><LF>" and IFS is ": ", then "cmd" will be
called with a number of arguments that depend on the shell and
the content of the current directory.
In the bourne shell (the syntax in the Bourne shell is `...`
instead of $(...)), that will be the list of files in the
current directory whose name contains a "-" but doesn't start
with a "." followed by "bar" and "baz".
In some Bourne like shells, it will be the same except that
there will be an empty element at the front, and with some
others both at the front and the tail. With zsh, the arguments
will be "", "*-*", "bar", "baz" and "".
When quoted or in scalar context, in other words, where it can't
expand to several words such as in:
cmd -- "$(cmd2)
var=$(cmd2)
case $(cmd2) in
.... and various others, that may depend on the shell such as
export var=$(cmd2) # only in bash and ksh
while
export $(echo a b) # export both a and b
Then, it is replaced with one string that is the collected
output (as long as it doesn't contain any NUL character) of the
command but where every trailing linefeed character has been
removed.
So, it is very important to understand that it is a very twisted
feature of the shell, to be used with care.
If one wants to have the output of a command in a single word
(argument), it is very important to quote it:
cmd -- "$(cmd2)"
If the fact that trailing linefeeds are removed is important,
such as is:
var=$(basename -- "$file")
Because the linefeed character can be found in a filename just
as any other character and possibly in trailing position, then a
workaround is:
var=$(basename -- "$file"; echo .)
var=${var%??}
if file is: "foo/bar<LF>", then basename outputs "bar<LF><LF>",
echo will output ".<LF>", so the whole output will be:
"bar<LF><LF>.<LF>" which the command substitution will shorten
to "bar<LF><LF>.". ${var%??} will remove two characters at the
end, so you'll be left with "bar<LF>" which is the basename of
the file.
When you want the output to be split into several words, then
almost certainly, you want to disable the filename generation as
in 99% of the cases, it doesn't make sense (that's a reason why
zsh disabled that weird /feature/ by default). And you have to
set the $IFS special variable, to specify how you want them to
be cut.
For instance, if a command outputs a list of strings, one per
line, you need to set the IFS parameter to a linefeed (newline)
character, and disable filename generation:
set -f # disable filename generation
IFS='
' # linefeed
for line in $(cmd)
do ...
done
(note that as the linefeed character is considered as a
/white-space/ character by the word splitting process, it
considers that any sequence of it makes one separator (and the
leading and trailing ones are discarded). In other words, no
empty element will result from the splitting, which means the
empty lines are discarded).
--
Stéphane
.
- Follow-Ups:
- Re: () $() etc., in Bash
- From: RoadHard
- Re: () $() etc., in Bash
- References:
- () $() etc., in Bash
- From: yusuf
- Re: () $() etc., in Bash
- From: Stephane CHAZELAS
- Re: () $() etc., in Bash
- From: yusuf
- Re: () $() etc., in Bash
- From: Chris F.A. Johnson
- () $() etc., in Bash
- Prev by Date: Re: Bash: command output to variable
- Next by Date: Re: a struct parser
- Previous by thread: Re: () $() etc., in Bash
- Next by thread: Re: () $() etc., in Bash
- Index(es):
Relevant Pages
|