Differences between revisions 8 and 9
Revision 8 as of 2011-06-03 08:37:28
Size: 3259
Editor: neurolysis
Comment: remove more useless cats and change final sentence to suit
Revision 9 as of 2011-06-03 13:03:11
Size: 3567
Editor: GreyCat
Comment: You CANNOT combine $(<file) and another command together. You must use cat. Also the page as written was portable, and you destroyed that without comment.
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
Command substitution is a very powerful concept of the UNIX shell. It is used to insert the output of a command in a certain place, e.g. Command substitution is a very powerful concept of the UNIX shell. It is used to insert the output of one command into a second command. E.g. with an assignment:
Line 11: Line 11:
This can be used as part of other commands, e.g. This can also be used with other commands besides assignments:
Line 29: Line 29:
    ip=$(awk "/$(</etc/myname)/"'{print $1}' /etc/hosts)     IPs=($(awk /"$(</etc/myname)"/'{print $1}' /etc/hosts))
Line 34: Line 34:
    echo "The IP is $(awk "/$(</etc/myname)/"'{print $1}' /etc/hosts)"     echo "The IPs are $(awk /"$(</etc/myname)"/'{print $1}' /etc/hosts | tr '\n' ' ')"
Line 38: Line 38:
Command substitutions create [[SubShell|subshells]], so any changes to variables, current directory, etc. inside the command substitution
affect only the rest of the substitution, and not the parent shell.
(For a better approach to discovering local IP addresses, see IpAddress.)

Command substitutions create [[SubShell|subshells]], so any changes to variables, current directory, etc. inside the command substitution affect only the rest of the substitution, and not the parent shell.
Line 54: Line 55:
    var=$(<file; printf x) var=${var%x}     var=$(cat file; printf x) var=${var%x}
Line 56: Line 57:

Of course, you could also use `$(cat file)` if you care about losing trailing newlines, but `$(<file)` is a tiny bit more efficient than calling `cat`.
Line 64: Line 63:
    IP=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`     IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`
    
    # Very Bourne-ish: use the positional params as a pseudo array
    set -- `awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`
Line 68: Line 70:
The use of `$(<file)` instead of `$(cat file)` is a [[Bashism]] that is slightly more efficient (doesn't require forking a `cat(1)` process) but obviously less portable.

Command Substitution

Command substitution is a very powerful concept of the UNIX shell. It is used to insert the output of one command into a second command. E.g. with an assignment:

    $ today=$(date)        # starts the "date" command, captures its output
    $ echo "$today"
    Mon Jul 26 13:16:02 MEST 2004

This can also be used with other commands besides assignments:

    $ echo "Today is $(date +%A), it's $(date +%H:%M)"
    Today is Monday, it's 13:21

This calls the date command two times, the first time to print the week-day, the second time for the current time.

Of course, this could just be done with:

    date "+Today is %A, it's %H:%M"

As with all substitutions, the results of a command substitution will undergo WordSplitting, unless the whole thing is inside double quotes.

Command substitutions may be nested within each other:

    IPs=($(awk /"$(</etc/myname)"/'{print $1}' /etc/hosts))

Notably, once inside a command substitution, the shell begins an entirely new quoting context. That is, double quotes inside the substitution do not match up with double quotes outside the substitution. So, things like this may be done:

    echo "The IPs are $(awk /"$(</etc/myname)"/'{print $1}' /etc/hosts | tr '\n' ' ')"

The outermost quotes delimit a single argument that will be passed to echo. The inner double quotes prevent word splitting or glob expansion on the results of the inner command substitution. The two sets of double quotes are independent of each other.

(For a better approach to discovering local IP addresses, see IpAddress.)

Command substitutions create subshells, so any changes to variables, current directory, etc. inside the command substitution affect only the rest of the substitution, and not the parent shell.

    $ var=$(cd ../../usr/bin; pwd)
    $ echo "$var"
    /usr/bin
    $ pwd
    /home/user

Command substitutions strip all trailing newlines from the output of the command inside them. This allows common cases such as foo=$(grep foo bar) to populate variables without needing a second step to remove the newline. Sometimes, you may want the newlines -- for example, when attempting to read an entire file into a variable without data loss (except NUL bytes):

    var=$(<file)   # strips trailing newlines

    # Workaround:
    var=$(cat file; printf x) var=${var%x}

Portability

The $(command) syntax is supported by KornShell, BASH, and PosixShell. Older shells (e.g. BourneShell) use the following syntax: `command`. Note that these are not the apostrophe characters '...', but small ticks going from the upper left to the lower right: `...`. These are often called "backticks" or "back quotes".

Nesting of command substitutions using the `...` syntax is more difficult. One must use backslashes:

    IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`
    
    # Very Bourne-ish: use the positional params as a pseudo array
    set -- `awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`

As one may imagine, this becomes rather unwieldy after two levels. FAQ 82 discusses the differences between $() and `` in more detail.

The use of $(<file) instead of $(cat file) is a Bashism that is slightly more efficient (doesn't require forking a cat(1) process) but obviously less portable.


CategoryShell

CommandSubstitution (last edited 2015-11-12 10:59:10 by AnthonyGeoghegan)