Why Can Back-Quotes and $() for Command Substitution Result in Different Output

Why are double quotes not grouped in command substitution output

You can use program1 | xargs program2 to solve your problem

echo '"Calibre Library" "VirtualBox VMs"' | xargs -exec ls

echo '"Calibre Library" "VirtualBox VMs"' | xargs ls

What is the difference between $(command) and `command` in shell programming?

The backticks/gravemarks have been deprecated in favor of $() for command substitution because $() can easily nest within itself as in $(echo foo$(echo bar)). There are other differences such as how backslashes are parsed in the backtick/gravemark version, etc.

See BashFAQ/082 for several reasons to always prefer the $(...) syntax.

Also see the POSIX spec for detailed information on the various differences.

What is the benefit of using $() instead of backticks in shell scripts?

The major one is the ability to nest them, commands within commands, without losing your sanity trying to figure out if some form of escaping will work on the backticks.

An example, though somewhat contrived:

deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print)

which will give you a list of all files in the /dir directory tree which have the same name as the earliest dated text file from December 2011 (a).

Another example would be something like getting the name (not the full path) of the parent directory:

pax> cd /home/pax/xyzzy/plugh
pax> parent=$(basename $(dirname $PWD))
pax> echo $parent
xyzzy

(a) Now that specific command may not actually work, I haven't tested the functionality. So, if you vote me down for it, you've lost sight of the intent :-) It's meant just as an illustration as to how you can nest, not as a bug-free production-ready snippet.

Command substitution: backticks or dollar sign / paren enclosed?

There are several questions/issues here, so I'll repeat each section of the poster's text, block-quoted, and followed by my response.

What's the preferred syntax, and why? Or are they pretty much interchangeable?

I would say that the $(some_command) form is preferred over the `some_command` form. The second form, using a pair of backquotes (the "`" character, also called a backtick and a grave accent), is the historical way of doing it. The first form, using dollar sign and parentheses, is a newer POSIX form, which means it's probably a more standard way of doing it. In turn, I'd think that that means it's more likely to work correctly with different shells and with different *nix implementations.

Another reason given for preferring the first (POSIX) form is that it's easier to read, especially when command substitutions are nested. Plus, with the backtick form, the backtick characters have to be backslash-escaped in the nested (inner) command substitutions.

With the POSIX form, you don't need to do that.

As far as whether they're interchangeable, well, I'd say that, in general, they are interchangeable, apart from the exceptions you mentioned for escaped characters. However, I don't know and cannot say whether all modern shells and all modern *nixes support both forms. I doubt that they do, especially older shells/older *nixes. If I were you, I wouldn't depend on interchangeability without first running a couple of quick, simple tests of each form on any shell/*nix implementations that you plan to run your finished scripts on.

I tend to favor the first, simply because my text editor seems to know what it is, and does syntax highlighting appropriately.

It's unfortunate that your editor doesn't seem to support the POSIX form; maybe you should check to see if there's an update to your editor that supports the POSIX way of doing it. Long shot maybe, but who knows? Or, maybe you should even consider trying a different editor.

GGG, what text editor are you using???

I read here that escaped characters act a bit differently in each case, but it's not clear to me which behavior is preferable, or if it just depends on the situation.

I'd say that it depends on what you're trying to accomplish; in other words, whether you're using escaped characters along with command substitution or not.

Side question: Is it bad practice to use both forms in one script, for example when nesting command substitutions?

Well, it might make the script slightly easier to READ (typographically speaking), but harder to UNDERSTAND! Someone reading your script (or YOU, reading it six months later!) would likely wonder why you didn't just stick to one form or the other--unless you put some sort of note about why you did this in the comments. Plus, mixing both forms in one script would make that script less likely to be portable: In order for the script to work properly, the shell that's executing it has to support BOTH forms, not just one form or the other.

For making a shell script understandable, I'd personally prefer sticking to one form or the other throughout any one script, unless there's a good technical reason to do otherwise. Moreover, I'd prefer the POSIX form over the older form; again, unless there's a good technical reason to do otherwise.

For more on the topic of command substitution, and the two different forms for doing it, I suggest you refer to the section on command substitution in the O'Reilly book "Classic Shell Scripting," second edition, by Robbins and Beebe. In that section, the authors state that the POSIX form for command substitution "is recommended for all new development." I have no financial interest in this book; it's just one I have (and love) on shell scripting, though it's more for intermediate or advanced shell scripting, and not really for beginning shell scripting.

-B.

command substitution breaks command substitution

it doesn't make sense, but try sourcing your sub-script

. "$(dirname "$0")"/setup_buildroot.sh "$BUILDROOT" # call the sub-script

results of Awk command different when executed from a tty versus a script

Because command substitution (using `backquotes`) treats backquotes specially. You will have to quote every \ again. Or use $() command substitution, as suggested elsewhere.

This should work better:

endlines=`cat ${src_path}/${bakfile} |awk '/\\\\\\./ {print NR;}'`


Related Topics



Leave a reply



Submit