From Schmid.wiki
Jump to: navigation, search

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 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

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...

Complex Examples

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
...