在字符串上运行sed,使用“echo”+“pipe”而不是“<<<<<

时间:2017-01-27 16:52:27

标签: bash sed io

通常我看到人们使用sed操作字符串如下:

echo "./asdf" | sed -n -e "s%./%%p"

我最近了解到我也可以这样做:

sed -n -e "s%./%%p" <<< "./asdf"

有理由避免后者吗? 例如,它是特定于bash的行为吗?

3 个答案:

答案 0 :(得分:9)

我应该如何从路径的开头修剪./(或执行其他简单的字符串操作)?

Bash的内置语法称为parameter expansion${s#./}将展开$s,其中包含任何前导./内部修剪,没有子进程或其他开销。 BashFAQ #100涵盖了许多其他字符串操作操作。

echo "$s" | ...... <<<"$s"之间有什么区别?

  1. 可移植性

    正如您所指出的,<<<在POSIX sh中不可用;这是一个ksh扩展,也可以在bash和zsh中使用。

    那就是说,如果你需要便携性,那么多线等价物并不遥远:

    ... <<EOF
    $s
    EOF
    
  2. 磁盘使用情况

    正如当前由bash实现的(并且作为一个可以更改的实现细节),<<<创建一个临时文件,填充,重新定向和重定向。如果您的TEMPDIR不在内存文件系统中,则可能会更慢,或者可能会产生客户流失。

  3. 流程开销

    管道(如echo foo | ...)创建子shell - 它会分离一个全新的进程,负责运行echo然后退出。当您运行result=$(echo "$s" | ...)时,该管道本身位于您的父shell的子shell中,而 shell的输出由父级读取。

    现代unixlikes付出了巨大的努力,尽可能地使fork()关闭子进程的开销很低,但即使这样,它也可以在循环中完成的操作中加起来 - 并且在诸如Cygwin它可能更重要。

  4. echo错误

    最后但并非最不重要 - <<<"$s"将精确地表示变量s的任何内容,但可以添加尾随换行符。相比之下,echo在其指定的行为中有很大的余地:它可以尊重反斜杠扩展或不依赖于对标准的可选XSI扩展的遵从性(以及是否存在或缺乏广泛但完全不符合标准的扩展-e和/或禁用它的运行时标志);标准不保证能够避免使用-n添加尾随换行符;和C。即使您正在使用管道,最好使用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" | ...
    

答案 1 :(得分:4)

如果可以帮助的话,完全使用sed是不可取的(参见Charles Duffy的回答);将字符串放在变量中,让shell使用POSIX兼容的参数扩展。

$ s="./asdf"
$ echo "${s#./}"
asdf

答案 2 :(得分:1)

我认为这里有两件事情。

  1. &LT;&LT;&LT;与管道
  2. sed(或其他外部命令)vs参数扩展
  3. 如果你可以通过扩展做一些事情,它很可能会更快,因为它可以保存正在启动的外部命令。

    然而,并非所有事情都可以通过扩展来完成。因此,您可能必须使用外部命令并将变量中的内容用作输入。在这种情况下,您必须根据可移植性考虑做出选择。至于表现,如果重要,你应该在你的背景下测试什么表现最好。