![在 find 的 -exec 选项中使用 sed 替换命令时出现问题](https://linux22.com/image/104221/%E5%9C%A8%20find%20%E7%9A%84%20-exec%20%E9%80%89%E9%A1%B9%E4%B8%AD%E4%BD%BF%E7%94%A8%20sed%20%E6%9B%BF%E6%8D%A2%E5%91%BD%E4%BB%A4%E6%97%B6%E5%87%BA%E7%8E%B0%E9%97%AE%E9%A2%98.png)
输入1:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed -n '1p' <(echo $1)' h {} \;
输出1:
./file with space
输入2:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed "1s_ _._" <(echo $1)' h {} \;
输出2:
./file.with.space
输入3:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed '1s_ _o_' <(echo $1)' h {} \;
输出3:
sed: -e expression #1, char 3: unterminated `s' command
为什么输出 3 出错?在这种情况下,单引号和双引号有何不同?
答案1
经过外壳解析后,第三条命令由find
, .
, -maxdepth
, 1
, -name
, * *
, -exec
, bash
, -c
, sed 1s_
, _o_ <(echo $1)
, h
, {}
,组成;
。该单词sed 1s_
是单个参数,因为空格位于单引号文字内,下一个参数也是如此。因此,当find
到达时./file with space
,它会bash
使用参数-c
, sed 1s_
, _o_ <(echo $1)
, h
,运行./file with space
。 shell 脚本是带有参数的sed 1s_
命令,这不是格式良好的 sed 脚本。sed
1s_
您尝试将单引号字符串放入单引号字符串中,但这是不可能的:第二个单引号结束单引号字符串。您可以使用'\''
结束单引号文字,然后放入单引号文字,并再次开始单引号文字:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed '\''1s_ _o_'\'' <(echo $1)' h {} \;
当然,<(echo $1)
包含通配符或除单个空格之外的空白序列的文件名会中断。我不知道你为什么写这个而不是<<<"$1"
.
答案2
我猜这是因为您正在关闭用于 bash 命令的单引号-C选项。
所以,你正在运行:bash
,第一个参数-c
,第二个参数sed 1s_
,第三个参数_o_ <(echo $1)
等等。像下面这样:
$ bash -c 'sed 1s_' '_o_ <(echo $1)'
第三个参数 ( '_o_ <(echo $1)'
) 传递给bash
,而不是传递给sed
。
要修复您的命令,您应该对参数使用双引号sed
:
$ find . -maxdepth 1 -name "* *" -exec bash -c 'sed "1s_ _o_" <(echo $1)' h {} \;