bash 执行变量(使用包含在 if 语句中创建的变量的命令)

bash execute variable (with command that held variable which is created inside if statement )

您好,我有如下脚本:

mode= loop1 or loop2
command1="screen -dm -S $name feh *.jpg"

if [ "$(screen -S loop1 -X select . ; echo $?)" != 0 ] && [[ $mode != "loop1" ]];then 
name="loop1"
eval "$command1"
elif [ "$(screen -S loop2 -X select . ; echo $?)" != 0 ] && [[ $mode != "loop2" ]] ;then
name="loop2"
eval "$command1"
else 
echo "error"
fi

基本上它会检查是否有名为 loop1 或 loop2 的屏幕会话,如果没有,它会评估变量 $command1,其中有另一个变量 $name,当 bash 进入循环时,它应该会发生变化。问题是变量 $command1 在 if 语句开始之前被全局初始化并且在那个时候没有变量 $date.

当循环评估 $command1 时,它不会在循环语句之前使用变量 $name 设置行。

我需要传递给变量 command1 变量名的值

你有什么线索吗?

它应该有效:

mode= loop1 or loop2
command1="screen -dm -S name feh *.jpg"

if [ "$(screen -S loop1 -X select . ; echo $?)" != 0 ] && [[ $mode !=     "loop1" ]];then 
eval "${command1/name/loop1}"
elif [ "$(screen -S loop2 -X select . ; echo $?)" != 0 ] && [[ $mode !=     "loop2" ]] ;then
eval "${command1/name/loop2}"
else 
echo "error"
fi

正如评论中已经指出的,这是一个常见问题解答:http://mywiki.wooledge.org/BashFAQ/050

一个明智的解决方法是将命令重构为参数化函数。条件语句也应该清除椒盐卷饼逻辑——打印命令的退出代码并将其与字符串零进行比较是重新实现 built-in if 条件语句的基本功能的笨拙方法!

mode=loop1 # or loop2
run_feh (} {
    screen -dm -S "" feh *.jpg
}

no_screen_of_loop () {
    ! screen -S "" -X select . && [[ "" != "" ]]
}

if no_screen_of_loop "loop1" "$mode"; then
    run_feh "loop1"
elif no_screen_of_loop "loop2" "$mode"; then
    run_feh "loop2"
else 
    echo "error" >&2    # note stderr
fi

如果在 $name 中的值是必要的,则需要进行一些额外的重构。

虽然 chepner 完全 更正您将 运行 陷入 Bash FAQ 050 问题,但您不应该尝试这样做。

这里更直接的问题是评估顺序问题。

当 shell 运行 这条线 command1="screen -dm -S $name feh *.jpg" 它在那个点扩展 $name (你会注意到,它是 之前 你已经为 name 变量赋值了)。

切换这些(组)行的顺序可以解决这个问题,但对 other Bash FAQ 050 问题没有任何作用。

此外,[ "$(screen -S loop1 -X select . ; echo $?)" != 0 ] 是测试命令是否成功的 return 代码的一种低效且不必要的方法。

[是一个命令(也称为test)。它 不是 if 语句语法的组成部分。

shell 中 if 语句的语法是 if <command>; then ... fi 其中 <command> 可以是 return 是 return 代码的任何内容适当地。 [恰好是那个space.

中常用的命令

但是如果你的命令(screen -S loop1 -X select .在这种情况下)已经returns success/failure适当那么你可以避免[ 完全使用你的命令。

if ! screen -S loop1 -X select . && [[ $mode != "loop1" ]];then 
    name="loop1"
elif ! screen -S loop2 -X select . && [[ $mode != "loop2" ]] ;then
    name="loop2"
else 
    echo "error"
fi