通常我看到人们使用sed操作字符串如下:
echo "./asdf" | sed -n -e "s%./%%p"
我最近了解到我也可以这样做:
sed -n -e "s%./%%p" <<< "./asdf"
有理由避免后者吗? 例如,它是特定于bash的行为吗?
答案 0 :(得分:9)
./
(或执行其他简单的字符串操作)? Bash的内置语法称为parameter expansion。 ${s#./}
将展开$s
,其中包含任何前导./
内部修剪,没有子进程或其他开销。 BashFAQ #100涵盖了许多其他字符串操作操作。
echo "$s" | ...
和... <<<"$s"
之间有什么区别?可移植性
正如您所指出的,<<<
在POSIX sh中不可用;这是一个ksh扩展,也可以在bash和zsh中使用。
那就是说,如果你需要便携性,那么多线等价物并不遥远:
... <<EOF
$s
EOF
磁盘使用情况
正如当前由bash实现的(并且作为一个可以更改的实现细节),<<<
创建一个临时文件,填充,重新定向和重定向。如果您的TEMPDIR
不在内存文件系统中,则可能会更慢,或者可能会产生客户流失。
流程开销
管道(如echo foo | ...
)创建子shell - 它会分离一个全新的进程,负责运行echo
然后退出。当您运行result=$(echo "$s" | ...)
时,该管道本身位于您的父shell的子shell中,而 shell的输出由父级读取。
现代unixlikes付出了巨大的努力,尽可能地使fork()
关闭子进程的开销很低,但即使这样,它也可以在循环中完成的操作中加起来 - 并且在诸如Cygwin它可能更重要。
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)
我认为这里有两件事情。
sed
(或其他外部命令)vs参数扩展如果你可以通过扩展做一些事情,它很可能会更快,因为它可以保存正在启动的外部命令。
然而,并非所有事情都可以通过扩展来完成。因此,您可能必须使用外部命令并将变量中的内容用作输入。在这种情况下,您必须根据可移植性考虑做出选择。至于表现,如果重要,你应该在你的背景下测试什么表现最好。