【问题标题】:How to echo single quotes from within shell in find exec如何在find exec中从shell中回显单引号
【发布时间】:2020-05-08 14:50:17
【问题描述】:

编辑

在以下答案之间,chepner's 和 Walter_A's 解决了问题。很快,要从 find 命令中打印单引号,您

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

(2) 定义一个局部变量,例如q="'" 在 find 命令之前并使用 $q 代替单引号。

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


原始问题:

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

  1. 在当前目录中查找特定文件;

  2. 为每个文件名在文本文件中附加一行,其中文件名以字符串“file”开头并用单引号括起来。

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

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

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

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

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

       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 -- "$0")""$SQ"' {} \;

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

【问题讨论】:

  • 不清楚为什么您的初始find 命令如此复杂。您可以使用find . -exec echo file {} \; 获得预期的输出。
  • 正如我所写,我删除了一个较长的 ffmpeg 部分,因为它不会影响问题。但问题出现的背景正是如此复杂。 --- 我可以要求解释一下反对票吗?
  • 我没有投反对票,所以我猜不出投反对票的人在想什么。但是对于您想要的内容,可能有一个更简单的解决方案,根本不涉及find
  • 这很好听。无论如何,我已经编辑并添加了完整的原始行

标签: bash shell exec single-quotes


【解决方案1】:

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

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

【讨论】:

  • 谢谢。这肯定比导出变量更优雅。您的答案也可以与 chepner's 结合使用,并使用 \047 而不是 $q。我也喜欢模式匹配——在这种情况下,basename 有点矫枉过正。
  • 当这个工作,看看stackoverflow.com/help/someone-answers
  • @Walter_A 当然,我已经对 chepner 的回答和你的回答投了赞成票,但我的投票没有出现,因为我已经失去了声誉(我一定是抢劫了一家银行或在某个地方被否决了)。您和 chepner 提供了两个不同的答案,但它们都很有效。我对接受的答案有点不确定,但我将编辑问题并重述它们。
【解决方案2】:

使用printf 代替echo

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

为避免为每个文件派生外部printf,请使用sh 来访问内置的shell,请使用

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

shell 中的循环和+ 终止符确保sh 将尽可能少地运行。通过使用\047 指示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 

【讨论】:

  • 我是。谢谢。
  • 感谢您的建议。我只是取消对 /dev/null 的重定向,因为我喜欢看到输出... ;-)
  • 啊,好的。我将把它拿出来并将重定向到mylist.txt 放回循环中。
  • 最好也添加一个换行符,因为每个文件名都需要一行: printf "file '%s'\n" "$f"
【解决方案3】:

这条线不是做同样的事情吗?

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

【讨论】:

    【解决方案4】:

    要在一对单引号中插入单引号,请使用'"'"'

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

    '"'"'的解释:

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

    "'" 插入单引号

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多