Bash run string formatted command in a for loop

时间:2016-06-10 16:10:20

标签: string bash for-loop

I am trying to run multiple similar commands using a for loop and string formatting.

I am able to create and then print the strings of the commands I would like to run:

$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;

But I want to enter these strings as a command. Based on other questions I was thinking that eval would do what I need:

$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

I was expecting(or hoping) the output would be equivalent to the output of:

$touch bar_file.txt; touch baz_file.txt;

The touch here is just an example. I'm more interested in how to format a string and then run it as a command. Thanks.

2 个答案:

答案 0 :(得分:3)

首先,这里不需要使用字符串格式来生成代码,或者通常 - 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',而不是执行危险内容并根据空格触摸多个文件。

答案 1 :(得分:1)

Instead of trying to put the whole command in a string, why not make a function to do the thing you want like:

update_file() {
    touch "$1"
}

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

then you can make that function do arbitrarily complex things with the files

As a general rule, variables hold data, not code. You can sometimes make it work putting code into data, but that way lies dragons. See here for some good reading on that