Bash Redirection And Pipes

Basic Redirection And Piping
Redirect 'stdout' and 'stderr' from 'make' command to "hell": $ make &>/dev/null Redirect 'stderr' to 'stdout' and pipe the whole thing to 'less': $ make 2>&1 | less

Subshells
Let's try reversing the output of 2 commands with the rev command. Below is a list of two 'printf' commands, separated by ';' and piped through rev: $ printf sdraw; printf kcab | rev sdrawback ... well, that's not right. It is of course because the 'sdraw' is printed first, and then the 'kcab' is printed in reverse. If we want the entire output of the 2 commands reversed, we could execute the 2 commands in a subshell, and then reverse the output of the subshell: $ bash -c "printf sdraw; printf kcab" | rev backwards ... fortunately, Bash has a shortcut syntax for executing commands in a subshell, using ' ': $ ( printf sdraw; printf kcab ) | rev backwards ... now the 2 commands inside the parentheses are executed in their own shell, and the output of that shell is piped through rev and thus reversed.

Use of a Subshell as an Output File
$ echo huba > huba.txt <- create a test file $ cp huba.txt >(cat)   <- as the target file, we use stdin to a new subshell, executing the 'cat' command

Duplication
Duplication of output can be performed using the Tee command: $ ( echo huba | tee >(cat) ) | cat huba               \____/ huba                  |_ this argument is normally an output file, but we                           use the feature mentioned in the previous section...

strace filtering
Show all 'open' calls during execution of 'ls': $ strace -o >(egrep ^open) ls

Mass Renaming
Very useful trick: 3. write the two filename lists                      ______ 4. rename in 2 columns                                 ____|_____ |                                          /          \ $ paste <(ls -1) <(ls -1 | sed -e 's/:_/-/g') | xargs -n2 mv         \______/ \__________________________/ |                 |    1. list all files   2. list all files but change ':_' to '-'

Names Back And fortH
$ (egrep -i "^(a.*e|e.*a)$" /usr/share/dict/propernames | tee >(rev) ) | column -c80 Adrienne       Archie          Esmerelda       ennA            aynE Aimee          Arlene          Eva             einnA           acirE Alice          Arne            enneirdA        eihcrA          adleremsE Anatole        Elsa            eemiA           enelrA          avE Andre          Emma            ecilA           enrA Anne           Enya            elotanA         aslE Annie          Erica           erdnA           ammE

____ 3. The whole thing inside the parantheses is executed in                         |        a subshell of its own. The resulting output can then |       be piped through a single command, here, it's 'column' _______________________|_________________________________________                 |  /                                                                 \                 | (egrep -i "^(a.*e|e.*a)$" /usr/share/dict/propernames | tee >(rev) ) | column -c80 <-' \__________________________________________________/  \________/                           |                                  | 1. find all names starting with a 'A' and      2. write it to stdout, and copy it to stdin ending with a 'E' or the opposite             of the 'rev' command, which is executed in a subshell

Multiplication Table
This example is basically 2 'while'-loops, one inside of the other. $ y=0;while [ $((y++)) -lt 5 ];do (x=0;while [ $((x++)) -lt 10 ];do echo $((x*y));done) | column; done 1      2       3       4       5       6       7       8       9       10 2       4       6       8       10      12      14      16      18      20 3       6       9       12      15      18      21      24      27      30 4       8       12      16      20      24      28      32      36      40 5       10      15      20      25      30      35      40      45      50

__ All this is executed in a subshell _________________________|_______________________                                   /                                                 \ $ y=0;while [ $((y++)) -lt 5 ];do (x=0;while [ $((x++)) -lt 10 ];do echo $((x*y));done) | column; done

Note that though the subshell inherits the environment from the parent shell, the subshell cannot change the environment of the parent shell. So, the example could have looked like this, and would still have worked (though the output is somewhat more boring): $ x=0;while [ $((x++)) -lt 5 ];do (x=0;while [ $((x++)) -lt 10 ];do echo $x;done) | column; done 1      2       3       4       5       6       7       8       9       10 1       2       3       4       5       6       7       8       9       10 ...