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
$ 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.
stdin 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 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...
Show all 'open()' calls during execution of 'ls':
$ strace -o >(egrep ^open) ls
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
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 ...