This is part of a bash find
loop, and I wondered which is more correct syntax and why?
filename="$(echo "$i" | cut -c5-)";
filename=`echo "$i" | cut -c5-`;
Both function for the purpose of getting the file name.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityThis is part of a bash find
loop, and I wondered which is more correct syntax and why?
filename="$(echo "$i" | cut -c5-)";
filename=`echo "$i" | cut -c5-`;
Both function for the purpose of getting the file name.
The POSIX $() form of command substitution is implemented (see Command Substitution), and preferred to the Bourne shell’s `` (which is also implemented for backwards compatibility).
So $(...)
is preferred over `...`
in anything new and Bash-specific you're writing¹. Backtick substitution doesn't nest well (you have to escape them), and has some slightly odd quoting behaviour. You can nest $(... $(...) ...)
arbitrarily much without issue. The manual describes the behaviour of the two as:
When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by ‘$’, ‘`’, or ‘\’. The first backquote not preceded by a backslash terminates the command substitution. When using the $(command) form, all characters between the parentheses make up the command; none are treated specially.
It's usually considered best practice to quote all string expansions to avoid word-splitting issues, including in places where it isn't strictly required, so "$(...)"
is also better practice here.
Finally, two relevant parts from that same wooledge page:
- It's also time you forgot about
`...`
. It isn't consistent with the syntax of Expansion and is terribly hard to nest without a dose of painkillers. Use$(...)
instead.- And for heaven's sake, "Use more quotes!" Protect your strings and parameter expansions from word splitting. Word splitting will eat your babies if you don't quote things properly.
¹Actually, even in POSIX sh
scripts, these are considered best practice. There are still weaker shells around, but you'll know if you're going to encounter them.
`...`
. Even the original version of ash
(initially a free reimplementation of the Bourne shell in 1989) supported $(...)
.
Aug 1, 2014 at 11:05
A comment about good-practice in your code not related to `...`
vs $(...)
:
In
filename="$(echo "$i" | cut -c5-)"
There are at least 4 potential caveats (minor unless there's an incentive to exploit them):
echo
for arbitrary data as you may get (depending on the echo
implementation or environment) problems with values of $i
that start with -
or contain backslashes. Best is to use printf
(here printf '%s\n' "$i"
) when dealing with arbitrary data.cut
and most text filtering utility are not very appropriate for dealing with file paths because they act on every line of their input. So here, you're taking the first 4 characters off every line of $i
(newline is as valid a character as any in file names). Best is to use filename=${i#????}
(though you may also want to take into account cases where $i
contains fewer than 4 characters).`...`
or $(...)
) removes every trailing newline character from the output of the command. So if $i
ends in newline characters, you'll miss them in $filename
. ${i#????}
also works around that.cut -c5-
or ${i#????}
removes 4 characters. Beware that in some locales, characters can be made of several bytes. You may want to take that into account. (also note that GNU cut
doesn't support multi-byte characters yet (cut -c
is the same as cut -b
)).