Commonly I see people manipulating strings using sed as follows:
echo "./asdf" | sed -n -e "s%./%%p"
I recently learned I can also do:
sed -n -e "s%./%%p" <<< "./asdf"
Is there a reason to avoid the latter? For instance, is it bash-specific behaviour?
The sed command is a common Linux command-line text processing utility. It's pretty convenient to process text files using this command. However, sometimes, the text we want the sed command to process is not in a file. Instead, it can be a literal string or saved in a shell variable.
Now, turn your attention to the sed (Stream Editor), which is best suited to be used in pipelines (data that comes from a pipe). The sed utility can be used to print the contents of a file, substitute a line (or multiple lines), and then save the file.
You should also be aware that sed outputs everything to standard out (STDOUT) by default. That means that, unless redirected, sed will print its output to the screen instead of saving it in a file.
'g' option is used in `sed` command to replace all occurrences of matching pattern. Create a text file named python.
./
from the beginning of a path (or perform other simple string manipulations)?Bash's built-in syntax for this is called parameter expansion. ${s#./}
will expand $s
with any leading ./
trimmed internal to the shell, with no subprocess or other overhead. BashFAQ #100 covers many additional string manipulation operations.
echo "$s" | ...
and ... <<<"$s"
?Portability
As you've noted, <<<
is not available in POSIX sh; this is a ksh extension also available in bash and zsh.
That said, if you need portability, the multiline equivalent is not far away:
... <<EOF
$s
EOF
Disk usage
As currently implemented by bash (and as an implementation detail subject to change), <<<
creates a temporary file, populates, it, and redirects from it. If your TEMPDIR
is not on an in-memory filesystem, this may be slower, or may generate churn.
Process overhead
A pipeline, as in echo foo | ...
, creates a subshell -- it forks off a completely new process, responsible for running echo
and then exiting. When you're running result=$(echo "$s" | ...)
, then that pipeline is itself in a subshell of your parent shell, and that shell has its output read by the parent.
Modern unixlikes go to significant effort to make fork()
ing off a subprocess low-overhead to the extent possible, but even then it can add up when in an operation done in a loop -- and on platforms such as Cygwin it can be even more significant.
echo
bugs
Last but not least -- <<<"$s"
will represent any contents of the variable s
precisely, with the exception that it can add a trailing newline. By contrast, echo
has a great deal of leeway in its specified behavior: It can honor backslash expansions or not depending on compliance with the optional XSI extensions to the standard (and presence or lack of the widespread but entirely noncompliant extension of -e
, and/or runtime flags that disable it); the ability to avoid addition of trailing newlines with -n
is not guaranteed by the standard; &c. Even if you're using a pipeline, it's better to use printf
:
# emit *exactly* the contents of "$s", with no newline added
printf '%s' "$s" | ...
# emit the contents of "$s", with an added trailing newline
printf '%s\n' "$s" | ...
# emit the contents of "$s", with '\t', '\n', '\b' &c replaced, and no added newline
printf '%b' "$s" | ...
Using sed
at all is not desirable if it can be helped (see Charles Duffy's answer); put the string in a variable and let the shell do it with POSIX-compatible parameter expansion.
$ s="./asdf"
$ echo "${s#./}"
asdf
I think there are two things at play here.
sed
(or other external command) vs parameter expansionIf you can do something with expansion, it is very likely it will be much quicker, as it saves an external command being launched.
However, not everything can be done with expansion. So you may have to use an external command and use as input something you have in a variable. In this case, you will have to make your choice based on portability considerations. As for performance, if it matters, you should probably test in your context what performs best.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With