【问题标题】:bash loop with pattern and quote characters带有模式和引号字符的 bash 循环
【发布时间】:2021-04-25 15:49:12
【问题描述】:
DESTINATION="example_substitute.txt"

echo "$DESTINATION"

DESTINATIONPATH="/home/example/test"

echo "$DESTINATIONPATH"

ARRAY=('EXP1' 'EXP2' 'EXP3 EXP4' 'EXP5 EXP6')

for n in "${ARRAY[@]}"; do

    (

    echo "$n"

    echo "sudo grep -RiIl --exclude-dir={_themes,_styleguide,_templates,_static,_RFCs,_glossary,_scripts,_blockdiag,_Definition} ' $n ' | xargs sed -i 's/ $n / :term:`$n` /g' ./*.rst" >> $DESTINATIONPATH/$DESTINATION

    )

done

我想从数组中合并我的 grep 命令并将其放入 $DESTINATIONPATH/$DESTINATION

作为新手 echo "$n" 带来正确的表达式。 第二个回声与引号斗争:

应该是:

sudo grep -RiIl --exclude-dir={_themes,_styleguide,_templates,_static,_RFCs,_glossary,_scripts,_blockdiag,_Definition} ' EXP1 ' | xargs sed -i 's/ EXP1 / :term:`EXP1` /g' ./*.rst

sudo grep -RiIl --exclude-dir={_themes,_styleguide,_templates,_static,_RFCs,_glossary,_scripts,_blockdiag,_Definition} ' EXP2 ' | xargs sed -i 's/ EXP2 / :term:`EXP2` /g' ./*.rst

sudo grep -RiIl --exclude-dir={_themes,_styleguide,_templates,_static,_RFCs,_glossary,_scripts,_blockdiag,_Definition} ' EXP3 EXP4 ' | xargs sed -i 's/ EXP3 EXP4 / :term:`EXP3 EXP4` /g' ./*.rst

sudo grep -RiIl --exclude-dir={_themes,_styleguide,_templates,_static,_RFCs,_glossary,_scripts,_blockdiag,_Definition} ' EXP5 EXP6 ' | xargs sed -i 's/ EXP5 EXP6 / :term:`EXP5 EXP6` /g' ./*.rst

【问题讨论】:

  • “与引号作斗争”是什么意思?输出是有效的,有什么问题吗?究竟是什么? (除了,它缺少EXP5 EXP6,我猜这是复制+粘贴的东西,对吧?)而xargs sed ... ./*.rst 没有意义 - 你可以删除grep 和xargs。
  • 对不起我的英语不好:输出应该在之前:sudo grep -RiIl --exclude-dir={_themes,_styleguide,_templates,_static,_RFCs,_glossary,_scripts,_blockdiag,_Definition} 'EXP1' | xargs sed -i 's/ EXP1 / :term:EXP1 /g' ./*.rst 如果你看 'EXP1' | xargs sed -i 's/ EXP1 / :term:EXP1 但它会中断,只有当我取出 ' 和 ` 我得到了错误的结果。对我来说重要的是得到这个:'EXP1'| xargs sed -i 's/ EXP1 / :term:EXP1
  • 您需要避开反引号,否则它们会扩展为 command substitution(在您的情况下,这可能会引发错误,因为 $n 的值不是命令)
  • 作为旁注,一般来说生成动态代码并不是你时间的最佳利用,你最好有一些可以参数化并调用的静态代码(函数或脚本文件)它与你的变量
  • 与您的原始问题并没有真正的关系,但是为什么要在单独的子进程中运行循环体?

标签: bash loops echo quotes


【解决方案1】:

您的问题是反引号对 ( `...` ) 被运行脚本的 shell 解析为command substitution,因此 shell 尝试将其中的值作为命令执行并将这对反引号及其内容替换为命令的输出。我假设您没有 EXP1 命令,因此它会引发错误并被空字符串替换,这会破坏您的输出中的 sed 命令。

为了达到您的预期输出,您应该简单地转义反引号(当在双引号字符串中找到单引号时,无需对单引号执行任何操作):

echo "sudo grep [...] ' $n ' | xargs sed -i 's/ $n / :term:\`$n\` /g' ./*.rst" >> $DESTINATIONPATH/$DESTINATION

但是,我假设您希望此文本稍后被解释为命令,无论您是要执行存储它们的文件、将它们复制/粘贴到 shell 中还是以任何其他方式。如果是这种情况,并且如果 EXP1 和 $n 的其他值此时不应被解释为命令,那么您实际上需要双重转义反引号:

echo "sudo grep [...] ' $n ' | xargs sed -i 's/ $n / :term:\\\`$n\\\` /g' ./*.rst" >> $DESTINATIONPATH/$DESTINATION

在此命令中,我们有一个转义的反斜杠,后跟一个转义的反引号,您当前的脚本将对其进行解释,并让它输出以下命令,我们在其中找到一个转义的反引号:

sudo grep [...] ' $n ' | xargs sed -i 's/ $n / :term:\`$n\` /g' ./*.rst

这样,当您执行此命令时,转义的反引号将被解释为实际字符,而不是被解析为命令替换,从而引发错误,因为没有这样的命令并破坏您的 sed 命令。

如您所见,这一切都相当复杂,这就是为什么我敦促您停止生成代码,而是将代码模板存储到脚本文件或函数中,然后简单地生成对它们的调用。

例如使用以下脚本,我们称之为 do_the_thing.sh :

#!/bin/bash
sudo grep [...] ' $1 ' | xargs sed -i 's/ $1 / :term:\`$1\` /g' ./*.rst

请注意,我已将 $n 替换为 $1,这是对该脚本将使用的第一个参数的引用。

此时可以将您当前脚本的循环体替换为/path/to/do_the_thing.sh "$n",而不必担心双重解释的影响,因为实际代码只会在您生成的调用被执行时被解释一次。

请注意,您需要使脚本可执行 (chmod +x /path/to/do_the_thing.sh),并且如果您生成的调用要从 do_the_thing.sh 脚本的同一目录执行,您可以使用相对路径(例如 do_the_thing.sh "$n")位于。

此外,由于这个额外的脚本带来的简单性,您完全可以质疑生成脚本的必要性。毕竟,执行您当前尝试生成的 5 个命令将变得像

for param in 'EXP1' 'EXP2' 'EXP3 EXP4' 'EXP5 EXP6'; do
    /path/to/do_the_thing.sh "$param"
done

【讨论】:

  • 这太棒了@Aaron!这太棒了!
  • @PierreGronau 真的不多,很高兴我能帮上忙!我认为您不能以您当前的声誉为答案投票,但如果您认为它解决了您的问题,请考虑 accepting 我的回答,这是表达感激之情的一种简单方式,它可以帮助未来遇到相同问题的用户选择合适的解决方案。
猜你喜欢
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 2014-02-16
  • 1970-01-01
相关资源
最近更新 更多