首页 > 解决方案 > 如何将 bash shell 字符串转换为命令

问题描述

我正在运行具有不同配置的不同程序。我尝试将内部循环中的字符串 ( kmeansand bayes) 转换为我在开始时定义的变量,这样我就可以运行程序并捕获控制台输出。用于记录每个程序的执行时间kmeans_timebayes_time

#!/bin/bash
kmeans="./kmeans -m40 -n40 -t0.00001 -p 4 -i inputs/random-n1024-d128-c4.txt"
bayes="./bayes -t 4 -v32 -r1024 -n2 -p20 -s0 -i2 -e2"
kmeans_time=0
bayes_time=0

for n in {1..10}
do 
    for prog in kmeans bayes
    do
        
        output=($(${prog} | tail -1))
        ${$prog + "_time"}=$( echo $kmeans_time + ${output[1]} | bc)
        echo ${output[1]}
    done
done

但是,我收到以下错误。似乎prog是作为字符串而不是我定义的命令执行的。此外,time变量字段的连接。我尝试了各种方法。这是如何在 Bash 中完成的?

./test.sh: line 11: kmeans: command not found
./test.sh: line 12: ${$app + "_time"}=$( echo $kmeans_time + ${output[1]} | bc): bad substitution

我想要做的是如下执行,它可以正常工作。

kmeans="./kmeans -m40 -n40 -t0.00001 -p 4 -i inputs/random-n1024-d128-c4.txt"
output=($($kmeans | tail -1))
# output[1] is the execution time
echo "${output[1]}"
kmeas_times=$kmeans_times+${output[1]}

我想迭代不同的程序并计算它们的每个平均执行时间

标签: bash

解决方案


我隐约猜测您正在寻找printf -v.

输入的字符串bayes不是一个有效的命令,也不是另一个程序的有效参数序列,所以我真的猜不出你希望它做什么。

此外,output不是一个数组,所以${output[1]}没有很好的定义。您是否尝试从线路中获取第一个令牌?你似乎把括号放错了位置output;但是您可以tail用一个简单的 awk 脚本替换调用,以提取您想要的令牌。

您的代码将始终添加kmeans_timeto的值output;如果你想使用由你命名的变量,$prog你可以使用间接扩展来指定变量的名称,但是你需要一个临时变量。

嗯,也许是这样的?希望这至少应该向您展示有效的 Bash 语法是什么样的。

kmeans_time=0
bayes_time=0

for n in {1..10}
do 
    for prog in kmeans bayes
    do
        case $prog in
           kmeans) cmd=(./kmeans -m40 -n40 -t0.00001 -p 4 -i inputs/random-n1024-d128-c4.txt);;
           bayes) cmd=(./bayes -t 4 -v32 -r1024 -n2 -p20 -s0 -i2 -e2);;
        esac
        output=$("${cmd[@]}" | awk 'END { print $2 }')
        var=${prog}_time
        printf -v "$var" %i $((!var + output))
        echo "$output"
    done
done

作为间接扩展的替代方法,可以使用关联数组来存储累积时间。(不过,仅限 Bash v5+。)

如果交替运行这两个程序并不重要,那么您的代码可能会被简化。

kmeans () {
    ./kmeans -m40 -n40 -t0.00001 -p 4 -i inputs/random-n1024-d128-c4.txt
}
bayes () {
    ./bayes -t 4 -v32 -r1024 -n2 -p20 -s0 -i2 -e2
}
get_output () {
    awk 'END { print $2 }'
}
loop () {
    time=0
    for n in {1..10}; do
    do
        output=("$@" | get_output)
        time=$((time+output))
        print "$output"
    done
    printf -v "${0}_time" %i "$time"
}

loop kmeans
loop bayes

也许还可以参见http://mywiki.wooledge.org/BashFAQ/050(“我正在尝试将命令放入变量中,但复杂的情况总是失败”)。


推荐阅读