用于运行多个选项卡程序的 Bash 脚本

用于运行多个选项卡程序的 Bash 脚本

我有以下 bash 脚本代码,用于在不同的终端选项卡中使用不同的输入参数打开 python 脚本的多个会话。

#!/bin/bash

cd /home/me/experiment

tab=" --tab-with-profile=Default"
options=()  #(--tab --title=Terminal)

cmds[1]="./new_path.py -s 593000 -f 593200"
titles[1]="0593000_0593200"

cmds[2]="./new_path.py -s 593200 -f 593400"
titles[2]="0593200_0593400"

cmds[3]="./new_path.py -s 593400 -f 593600"
titles[3]="0593400_0593600"

cmds[4]="./new_path.py -s 593600 -f 593800"
titles[4]="0593600_0593800"

cmds[5]="./new_path.py -s 593800 -f 594000"
titles[5]="0593800_0594000"



for i in 1 2 3 4 5; do
  options+=($tab --title="${titles[i]}"  -e "bash -c \"${cmds[i]} ; bash\"" )          
done

gnome-terminal "${options[@]}"


exit 0

如何避免使用 for 循环和 bash 脚本变量多次输入相同的命令?

答案1

您可以将脚本缩短为:

#!/bin/bash

cd /home/me/experiment

args=()
for ((step=200, s=593000; (f=s+step)<=594000; s+=step)); do
    cmd="./new_path.py -s $s -f $f";  printf -v title '%07d_%07d' $s $f
    args+=(--tab-with-profile=Default -t $title -e "sh -c \"$cmd; bash\"")
done

gnome-terminal "${args[@]}"

为了消除重复,我完全删除了cmds和数组,并且titles将这些字符串的构造移到循环中,以便可以实现自动化。

我当然测试过这个;虽然在我的测试中我使用了mate-terminal而不是gnome-terminal。它们非常相似,mate-terminal都是 的一个分支gnome-terminal,如果因为这种差异而出现任何问题,我会非常惊讶;mate-terminal的功能是 提供的功能的子集gnome-terminal。最重要的是,两者都接受相同的--tab-with-profile-t-e选项。

如果您感兴趣的话,下面将更详细地解释上述代码的工作原理以及为什么选择该实现。


我没有循环遍历序列1 2 3 4 5,因为这对于问题来说毫无意义,而是将s传递给./new_path.pyafter 的值设为循环变量-s。我还定义f并确保它在循环的每次迭代中都取一个比 大 200 的值;这就是传递给after 的s值。./new_path.py-f

这使得构建每个迭代cmdtitle字符串变得容易。(是传递给之后的cmd值,是传递之后的值。)gnome-terminal-etitle-t

  • 制作cmd特别简单。s并且f可以不加修改地出现在字符串中,在双引号表达式中取消引用为$s和。$f
  • 对于title我注意到你手动编写的字符串中的前导零(例如)。我推断你可能希望在标题数字少于七位时用零填充,并使用 bash 的"0593000_0593200"printf 内置为了达成这个。

在编写循环时,有几种可能的构造可供选择。除了更常见的语法外,bash 还支持 C 风格的语法,我决定使用它。for variable in listfor(( initialization; condition; increment-or-other-action))

我决定如何编写循环的目标包括:

  • 使得稍后修改循环时,每个数字只需在一个地方更改(例如,避免200在代码中多次出现),
  • 反映正在解决的根本问题的逻辑。

在 bash 中,数字序列通常最好用(或仅适用于连续序列)生成。但是{start..end..step}{start..end}括号扩展之前执行shell 参数扩展, 所以startend, 和step不能是变量(如$step)。

循环(以及循环内的设置)可以解决这个问题,如果我只关心代码的简易维护,我可能会那样做。for s in seq 593000 593800 $stepf=$((s+step))

根据你原来的脚本,似乎正在解决的根本问题是,或者是就像是, 这:

  • 执行(某些实验或计算)的运行。
  • ./new_path.py改变一些重要参数,其起始值和最终值通过-s和指定-f
  • 重要参数范围从593000到594000。
  • 以 200 为块依次变化。通过并行运行五个这样的任务来覆盖范围。

这表明,以这样的方式编写循环很有价值:最低-s最高-f被指定(而不是最低值和最高-s值)。我使用了 C 风格的for ((...))循环,它以相当简洁和可读的方式实现了这一点。

请注意,这不是唯一的方法,也没有任何一种“正确方法”。特别是,我可以在循环之前定义stepand max(并初始化s为其最小值),然后使用带有算术比较的 while 循环(通过((<=,或[[-le条件中含有)。

与您的原始脚本相比,我做了一些其他更改,但这些更改并不大,完全是风格偏好的问题。

  • 我将其重命名options为,args因为“选项”通常专门用于表示标志(例如以 和 开头的标志---,而不是所有命令行参数。

  • 由于该+=运算符用于构建参数数组,而不是最终的命令字符串本身,因此其元素中不需要前导或尾随空格。所以我删除了 之前的前导空格--tab-with-profile

  • 在传递给gnome-terminal,我将其改为--title以便-t与 的选择保持一致-e。 (-t是 的缩写形式--title=-e是 的缩写形式--command=。)这也使它更容易阅读,因为它可以$title成为一个单独的数组元素,而不必像 那样组合成字符串"--title=$title"

  • 我使用sh -c ...而不是bash -c ...作为传递给的命令gnome-terminal,因为通用sh(Ubuntu 中更简单、更轻量dash)足以完成用 链接两个简单命令的任务;。(我没有bash将after更改;sh,因为完成后在每个选项卡中运行的交互式 shell./new_path.py当然应该仍然是 bash。)

    在此背景下,这无疑是不是这是性能方面的考虑,只是风格问题。我不是建议使用sh -cbash -c不是正确的方式或客观上更可取。

相关内容