如何在 find exec 中回显 shell 中的单引号

How to echo single quotes from within shell in find exec

编辑

在以下答案之间,chepner 和 Walter_A 解决了问题。简而言之,要从查找命令中打印单引号,您

(1) 使用 "\047" 代替单引号或

(2) 定义一个局部变量,例如q="'" 就在查找命令之前,并使用 $q 而不是单引号。

因此,这个特定问题的解决方案不是使用 printf 代替 echo 或 for 循环代替 find...exec,而是两者printf 和 for 可能有助于改进代码。


原始问题:

我正在尝试使以下过程自动化:

  1. 在当前目录中查找某些文件;

  2. 为每个文件名在文本文件中附加一行,其中文件名前面有字符串 "file " 并用单引号括起来。

这实际上是任务的简化版本:我搜索的文件是视频文件,ffmpeg 在尝试将它们的名称写入文本文件之前对它们做了一些处理。文本文件的目的是稍后连接输出文件。完整的行是这样的:

    find . -maxdepth 1 -iname "name*" -exec sh -c 'ffmpeg -i "[=11=]" -ss 3.3 -c:v libx264 -crf 20 -pix_fmt yuv420p -c:a copy "out/""[=11=]"; echo "file ""\'""$(basename -- "[=11=]")">>mylist.txt' {} \;

但是,视频部分效果很好,我只关注单引号的打印(在屏幕上或文件中),这给我带来了麻烦。如果我试试这个:

      find . -iname "*" -exec sh -c 'echo "file ""[=12=]"' {} \;

我得到了,如预期的那样:

       file a1.mp4
       file a2.mp4
       [...]

我现在在文件名$0前加上单引号;在双引号或单引号之间,是否转义(如果转义,我也尝试过不带引号),在美元符号后的引号之间,但我得到的只是符号“>”后跟闪烁的光标,等待更多输入。

我尝试将单引号插入为:"\'", '\'', \', $''', $'\'', $"\'"; 我把它放在字符串 "file " 中,带或不带单引号或双引号;我在 exec 中设置了一个变量 v="file ""\'""$0" 并在双引号之间回显了 it。不过,我所有的尝试都失败了。最好理解为什么。或许这里有值得学习的地方。。。谢谢大家的指点。

______________ 解决方法 _______________

我找到了解决方法。我写了一个 bash 文件,而不是从终端发出单个命令。在查找行之前,我导出一个变量 SQ="'"。然后我的查找行变成:

    find . -maxdepth 1 -iname "*" -exec sh -c 'echo "file ""$SQ""$(basename -- "[=14=]")""$SQ"' {} \;

并且有效。也许出现在导出变量中的单引号与出现在 shell 或局部变量中的字符串中的单引号的处理方式不同?

使用 printf 而不是 echo

find . -iname "*" -exec printf "file '%s'" {} \;

为避免为每个文件分叉外部 printf,使用 sh 访问 shell 内置函数,使用

find . -iname "*" -exec sh -c 'for f; do printf "file 7%s7\n" "$f"; done' sh {} +

shell 和 + 终止符中的循环确保 sh 将 运行 尽可能少。通过使用 7 指示 printf 输出单引号可以避免引用问题。


更新:我会用一个简单的 shell 循环替换 find

for full in name*; do
    f=$(basename "$full")
    ffmpeg -i "$full" -ss 3.3 -c:v libx264 -crf 20 -pix_fmt yuv420p -c:a copy "out/$f"
    printf "file '%s'\n" "$f" >> mylist.txt
done 

这行不是做同样的事情吗?

find . -iname "*" -exec sh -c 'echo "file" "$(basename [=10=])"' {} \;

要在一对单引号内插入一个单引号,请使用 '"'"':

find . -maxdepth 1 -iname "*" -exec sh -c 'echo "file '"'"'$(basename -- "[=10=]")'"'"'"' {} \;

'"'"'的解释:

第一个 ' 关闭前一个单引号

"'" 插入单引号

最后 ' 重新启动单引号字符串。

为临时变量分配引号(我也删除了路径)。

q="'" find . -iname "*" -exec sh -c 'echo "file $q${0##*/}$q"' {} \;