The backquotes mean command substitution: the result of expanding `pidof transmission-gtk`
is the output from running the command pidof transmission-gtk
. An alternate way of writing `pidof transmission-gtk`
is $(pidof transmission-gtk)
, and that alternate way is recommended (it has no downsides and it avoids issues when the command inside the backquotes itself contains quotes).
The double quotes around that prevent the result of the command substitution from being split into separate words and interpreted as wildcard patterns. If you're just starting with shell scripting, don't worry about this, just remember to always put double quotes around command substitutions. The same goes for variable substitutions, e.g. always write "$foo"
, never plain $foo
.
This snippet as written doesn't make any sense: the test contains a single word, which will be something like =0
(if there is no running transmission-gtk
process) or 1234=0
(if there is a matching process) or 123 456=0
(a single word in shell terminology, even if it happens to contain a space). A single word in a test is always considered true. To test whether a string is equal to another string, write [ "string1" = "string2" ]
(there must be a space on each side of the brackets, and on each side of the operator). To test for numerical equality, use the -eq
operator, e.g. [ 1 -eq 01 ]
is true.
Here, there are two equivalent ways of testing whether there is a running transmission-gtk
process:
Test whether the output is empty:
if [ -z "$(pidof transmission-gtk)" ]; then …
Test whether the return status of the pidof
is nonzero, indicating failure. Since the output of the command is not used, redirect it to /dev/null
(the great void).
if ! pidof transmission-gtk >/dev/null; then
You could do the following using some implementations of find
and xargs
like this.
$ find . -type f -print0 | xargs -r0 ./myscript
or, standardly, just find
:
$ find . -type f -exec ./myscript {} +
Example
Say I have the following sample directory.
$ tree
.
|-- dir1
| `-- a\ file1.txt
|-- dir2
| `-- a\ file2.txt
|-- dir3
| `-- a\ file3.txt
`-- myscript
3 directories, 4 files
Now let's say I have this for ./myscript
.
#!/bin/bash
for i in "$@"; do
echo "file: $i"
done
Now when I run the following command.
$ find . -type f -print0 | xargs -r0 ./myscript
file: ./dir2/a file2.txt
file: ./dir3/a file3.txt
file: ./dir1/a file1.txt
file: ./myscript
Or when I use the 2nd form like so:
$ find . -type f -exec ./myscript {} +
file: ./dir2/a file2.txt
file: ./dir3/a file3.txt
file: ./dir1/a file1.txt
file: ./myscript
Details
find + xargs
The above 2 methods, though looking different, are essentially the same. The first is taking the output from find, splitting it using NULLs (\0
) via the -print0
switch to find. The xargs -0
is specifically designed to take input that's split using NULLs. That non-standard syntax was introduced by GNU find
and xargs
but is also found nowadays in a few others like most recent BSDs. The -r
option is required to avoid calling myscript
if find
finds nothing with GNU find
but not with BSDs.
NOTE: This entire approach hinges on the fact that you'll never pass a string that's exceedingly long. If it is, then a 2nd invocation of ./myscript
will get kicked off with the remainder of subsequent results from find.
find with +
That's the standard way (though it was only added relatively recently (2005) to the GNU implementation of find
). The ability to do what we're doing with xargs
is literally built into find
. So find
will find a list of files and then pass that list as as many arguments as can fit to the command specified after -exec
(note that {}
can only be last just before +
in this case), running the commands several times if needed.
Why no quoting?
In the first example we're taking a shortcut by completely avoiding the issues with the quoting, by using NULLs to separate the arguments. When xargs
is given this list it's instructed to split on the NULLs effectively protecting our individual command atoms.
In the second example we're keeping the results internal to find
and so it knows what each file atom is, and will guarantee to handle them appropriately, thereby avoiding the whoie business of quoting them.
Maximum size of command line?
This question comes up from time to time so as a bonus I'm adding it to this answer, mainly so I can find it in the future. You can use xargs
to see what the environment's limit like so:
$ xargs --show-limits
Your environment variables take up 4791 bytes
POSIX upper limit on argument length (this system): 2090313
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2085522
Size of command buffer we are actually using: 131072
Best Answer
Text between backticks is executed and replaced by the output of the command (minus the trailing newline characters, and beware that shell behaviors vary when there are NUL characters in the output). That is called command substitution because it is substituted with the output of the command. So if you want to print 5, you can't use backticks, you can use quotation marks, like
echo "$b"
or just drop any quotation and useecho $b
.As you can see, since
$b
contains 5, when using backticksbash
is trying to run command5
and since there is no such command, it fails with error message.To understand how backticks works, try running this:
cat /etc/passwd |head -n1
should print first line of/etc/passwd
file. But since we use backticks, it doesn't print this on console. Instead it is stored inA
variable. You can echo$A
to this. Note that more efficient way of printing first line is using commandhead -n1 /etc/passwd
but I wanted to point out that expression inside of backticks does not have to be simple.So if first line of /etc/passwd is
root:x:0:0:root:/root:/bin/bash
, first command will be dynamically substituted by bash toA="root:x:0:0:root:/root:/bin/bash"
.Note that this syntax is of the Bourne shell. Quoting and escaping becomes quickly a nightmare with it especially when you start nesting them. Ksh introduced the
$(...)
alternative which is now standardized (POSIX) and supported by all shells (even the Bourne shell from Unix v9). So you should use$(...)
instead nowadays unless you need to be portable to very old Bourne shells.Also note that the output of
`...`
and$(...)
are subject to word splitting and filename generation just like variable expansion (in zsh, word splitting only), so would generally need to be quoted in list contexts.