It is time to correct a few of my not-so-precise statements above. Suffice it to say i learned something new myself yesterday. Many thanks to RudiC who pointed out my misconception to me.
A small explanation first of what is only a little trick: ps -fe
shows all processes and if i would filter that through grep sleep
it would end up finding itself (most times - it is a race condition). To avoid that (and a second grep
like the often seen:
ps -fe | grep something | grep -v grep
at the same time) i use leep
as a regular expression here. This will also search for "sleep" but since the regexp looks different to the string searched for it will not find itself, thus saving the second grep
.
Now to something else, since i explained something not quite adequate and as a beginner you should learn it the right way, not the wrong way. When i talked about "process substitution" and "command substitution" above my wording was not quite accurate. Here is the truth:
The construct ( ... )
basically opens up a "subshell": it starts a shell and runs the commands inside the braces like a separate (unnamed) script in that shell. Afterwards this shell is closed and normal operation resumes. Note that this has the side effect of removing changes in variables you did inside the subshell:
var="abc"
( var="XYZ"
command1
command2
)
echo $var
will result in "abc", not "XYZ". Many of the following concepts will be based on such a subshell.
Let us get to "process substitution". A process substitution happens if you use the subshell mechanism to redirect input to or output from such a subshell. In case of redirecting the output it this will offer the ability to "string together" output of differing commands.
Example: you have two files and you want to search in one for one thing and for something else in the other but you want to process the results the same way. Like this:
( grep "something" file1 ; grep "otherthing" file2 )> ....
Here is a more complex example from the ksh manual:
paste <(cut -f1 file1) <(cut -f3 file2) | tee >(process1) >(process2)
This cuts field 1 from file1
and field 3 from file2
, sends these to paste
so that a "table" with these two fields is created. This is in turn sent to process1
as well as process2
and also displayed on screen (all by the tee
command).
Again, always keep in mind thaat all this is done in subshells, so your variable scope (and other things too) might not be what you think it is.
Finally there is "command substitution". This is done by $( ... )
(sometimes ${ ... ; }
) and works similar to process substitution but you can treat the output of the whole block as a string/number:
var=$(tail -n 1 /some/file)
tail -n 1
will extract the last line of a file. The whole construct will assign this last line as a string to the variable. Again, this is done in a subshell so you will have to watch variable scope, etc., because the subshell is left at the end.
Here is another example: sometimes you may want to preserve a return code in a more complex way. Say you have 3 commands and if any of them fails you want to consider all of them failed:
MyRetVal=$( RC=0
if ! command1 ; then RC=1 ; fi
if ! command2 ; then RC=1 ; fi
if ! command3 ; then RC=1 ; fi
echo $RC
)
If all commands succeed RC will be "0", otherwise "1". This is printed by the echo
command to stdout but assigned to MyRetVal
by the command substitution.
I hope this helps.
bakunin