【问题标题】:Bash run string formatted command in a for loopBash 在 for 循环中运行字符串格式的命令
【发布时间】:2016-10-11 16:30:43
【问题描述】:

我正在尝试使用 for 循环和字符串格式运行多个类似的命令。

我能够创建并打印我想运行的命令的字符串:

$foo=( "bar" "baz" )
$for ((j=0;j<2;++j)); do printf "touch %s_file.txt; " "${foo[j]}"; done
touch bar_file.txt; touch baz_file.txt;

但我想将这些字符串作为命令输入。基于其他问题,我认为eval 可以满足我的需要:

$for ((j=0;j<2;++j)); do eval "touch %s_file.txt; " "${foo[j]}"; done
-bash: bar: command not found
-bash: baz: command not found

我期待(或希望)输出等同于:

$touch bar_file.txt; touch baz_file.txt;

这里的touch 只是一个例子。我对如何格式化字符串然后将其作为命令运行更感兴趣。谢谢。

【问题讨论】:

  • 您是否有理由按索引而不是for prefix in "${foo[@]}"; do 进行迭代?根本不需要j
  • 顺便说一句——您能否更清楚地了解为什么您要尝试使用字符串格式?如果您采用最佳实践方法,它会产生大量安全隐患。
  • @CharlesDuffy 我对 bash 相当陌生,所以我并不总是知道最佳实践是什么。就使用计数器进行循环而言,在我的实际用例中,我正在循环多个数组,并使用j 对它们进行索引。真的,我正在使用字符串格式,因为这是我知道该怎么做的事情。很高兴知道这不是执行此操作的正确方法,我将研究替代方案。感谢您的建议!
  • Re:迭代多个数组,如果你的 shell 是 bash 4.3 或 ksh93,你可能会考虑使用 namevars。也就是说,有效地做到这一点在很大程度上是一个很好的例子。

标签: string bash for-loop


【解决方案1】:

首先,这里不需要使用字符串格式来生成代码,或者一般来说——BashFAQ #50 描述了用例和更好的实践替代方案。这可以像下面这样简单:

for j in in "${foo[@]}"; do touch "${j}_file.txt"; done

其次,如果您必须,请这样做:

printf -v cmd 'touch %q_file.txt; ' "${foo[@]}"
eval "$cmd"

这将设置cmd='touch bar_file.txt; touch baz_file.txt ',然后执行它。

在稍后将由 shell 解析内容时使用%q(与eval 一样)确保您的数组元素的格式化方式能够在 shell 解析中存活——所以如果您有foo=( "name with spaces" 'name with $(rm -rf $HOME) dangerous content' ) ,您将正确触摸'name with spaces_file.txt''name with $(rm -rf $HOME) dangerous content_file.txt',而不是执行危险内容并根据空格触摸多个文件。

【讨论】:

    【解决方案2】:

    与其尝试将整个命令放在一个字符串中,不如创建一个函数来做你想做的事情:

    update_file() {
        touch "$1"
    }
    
    foo=( "bar" "baz" )
    for ((j=0;j<2;++j)); do
        update_file "$(printf "%s_file.txt" "${foo[j]}")"
    done
    

    然后你可以让这个函数对文件做任意复杂的事情

    一般来说,变量保存的是数据,而不是代码。有时你可以让它工作,将代码放入数据中,但那是龙。请参阅here 了解有关此内容的一些好读物

    【讨论】:

    • 其实,等等,对不起,我错过了你拿出eval。对不起;该评论不适用。
    • (相反,如果没有eval,它将是"$(printf '%s_file.txt' "${foo[j]}" )",在扩展周围加上引号以防止字符串拆分和全局扩展,%s 用于发出空格等字面意思) .
    • @CharlesDuffy 我真的打败了你 ;)
    • @EricRenouf 感谢您的建议和链接,它非常有用。
    • ...虽然,update_file "${foo[j]}_file.txt" 可能会做同样的事情。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-05
    • 2014-07-31
    • 1970-01-01
    • 2014-03-01
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多