在 find 的 -exec 选项中使用 sed 替换命令时出现问题

在 find 的 -exec 选项中使用 sed 替换命令时出现问题

输入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 脚本。sed1s_

您尝试将单引号字符串放入单引号字符串中,但这是不可能的:第二个单引号结束单引号字符串。您可以使用'\''结束单引号文字,然后放入单引号文字,并再次开始单引号文字:

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 {} \;

相关内容