Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running sed on string, benefit of using "echo" + "pipe" over "<<<" [duplicate]

Tags:

bash

io

sed

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?

like image 309
Sigve Karolius Avatar asked Jan 27 '17 16:01

Sigve Karolius


People also ask

Can you use sed on a string?

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.

Can you use sed in pipes?

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.

Does sed output to stdout?

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.

Which of the following is used with sed to replace a single character with new text?

'g' option is used in `sed` command to replace all occurrences of matching pattern. Create a text file named python.


3 Answers

How should I trim ./ 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.


What are the differences between echo "$s" | ... and ... <<<"$s"?

  1. 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
    
  2. 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.

  3. 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.

  4. 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" | ...
    
like image 193
Charles Duffy Avatar answered Sep 28 '22 10:09

Charles Duffy


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
like image 45
chepner Avatar answered Sep 28 '22 11:09

chepner


I think there are two things at play here.

  1. <<< vs. pipelines
  2. sed (or other external command) vs parameter expansion

If 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.

like image 32
Fred Avatar answered Sep 28 '22 11:09

Fred