在 bash 中,给定这些文件:
$ cat noquotes.txt
s/a/b/g
$ cat quotes.txt
"s/a/b/g"
为什么
$ echo "aaa" | sed -e $(cat noquotes.txt)
bbb
成功了,但是
$ echo "aaa" | sed -e $(cat quotes.txt)
sed: 1: ""s/a/b/g"
": invalid command code "
失败?
如果set -x
先运行,那么我看到
$ echo "aaa" | sed -e $(cat noquotes.txt)
+ echo aaa
++ cat noquotes.txt
+ sed -e s/a/b/g
bbb
和
$ echo "aaa" | sed -e $(cat quotes.txt)
+ echo aaa
++ cat quotes.txt
+ sed -e '"s/a/b/g"'
sed: 1: ""s/a/b/g"
": invalid command code "
因此,似乎在 的内容周围插入了额外的引号noquotes.txt
,但在 的内容周围没有插入额外的引号quotes.txt
。
答案1
命令行处理中有一个步骤称为报价删除步。这通常是执行命令之前发生的最后一件事,它会删除用于在命令中引用字符串的外部引号集。
对于诸如这样的命令
sed -e "s/a/b/g"
此步骤确保为该sed
命令提供字符串s/a/b/g
作为其最后一个参数,并且不是 "s/a/b/g"
。
"s/a/b/g"
当您在命令替换中使用文件读取字符串时cat
,引号不会被删除,因为它们不是原始命令的一部分(它们是从文件读取的数据的一部分)。
这意味着sed
将接收文字字符串"s/a/b/g"
作为要运行的表达式,因此它抱怨它不理解初始值"
(它期望一个sed
命令)。
至于跟踪的输出set -x
,仅将其视为调试输出。 shellbash
会在跟踪中包含某些字符的字符串周围添加引号,因此它并不表示任何单个参数的引用内容实际上是或者被调用的实用程序如何解释它。
顺便说一句,要sed
在文件上运行编辑脚本,请使用以下-f
选项:
sed -f noquotes.txt <<<"aaa"
此外,y
命令 insed
可用于在一组单个字符之间进行音译,比使用 with 替换更有效s
。您的s/a/b/g
替换最好写为y/a/b/
.
如果这是仅有的如果您需要执行的操作,那么使用更简单的tr
实用程序可能会更有效:
tr a b <<<"aaa"
答案2
因此,似乎在 noquotes.txt 的内容周围插入了额外的引号,而不是在quotes.txt 的周围插入了额外的引号。
这只是 Bash 的帮助。您会注意到,只要有 Bash 解释的符号,它就会在事物周围加上引号。它的行为就像您一样,仅在必要时使用引号。尝试将以下任何内容放入quotes.txt:
s/a$/a/g
s/"hi"/"bye"/g
这个清单可以列很长。
现在回到你原来的问题。首先,你sed
打印出一条奇怪的消息。很set -x
明显,输入是"s/a/b/g"
,而不是""s/a/b/g"
。我不会相信这个消息。以下是 GNU sed 4.2.1 打印的内容"s/a/b/g"
:
$ sed -e '"s/a/b/g"'
sed: -e expression #1, char 1: unknown command: `"'
非常清楚:由于第一个字符是命令名称,并且没有名为 的命令"
,sed
因此不知道该怎么做。