在单行 bash 循环中使用 &(与号)

在单行 bash 循环中使用 &(与号)

我已经成功地使用了这个命令,它更改了配置文件中的变量,然后在循环中执行 Python 脚本:

for((i=114;i<=255;i+=1)); do echo $i > numbers.txt; python DoMyScript.py; done

由于每个DoMyScript.py实例在终止之前需要大约 30 秒的时间运行,因此我想将它们降级到后台,同时可以生成下一个实例。

我尝试了我熟悉的方法,添加了一个&符号,如下所示:

for((i=114;i<=255;i+=1)); do echo $i > numbers.txt; python DoMyScript.py &; done

但是,这会导致以下错误:

-bash: syntax error near unexpected token `;'

答案1

去掉;后面的&。这是一个句法要求

for((i=114;i<=255;i+=1)); do echo $i > numbers.txt;python DoMyScript.py & done

答案2

鉴于斯蒂芬的评论1_CR的回答,你可能想要:

for i in {114..255}; do { echo $i > numbers.txt && python DoMyScript.py; } & done

答案3

失去;

for((i=114;i<=255;i+=1)); do echo $i > numbers.txt;python DoMyScript.py & done

答案4

正如其他答案所说:

  • 问题出;在之后&
  • 删除;后面的 将&导致命令运行时不会出现 shell 语法错误。但是,它不太可能正常运行,因为它会产生竞争条件。

OP 表示他通过添加 3 秒延迟解决了竞争条件。

没有人提到:

  • 今天延迟 3 秒可能有效。明天,计算机可能会变得更加缓慢,并且可能会再次出现故障。明年,脚本可能会被修改得更加耗时,并且可能会再次失败。如果将延迟增加一个数量级(我的意思是 30 秒),失败的可能性就会下降。当然,这意味着脚本进程将(可能/大概)基本上按顺序运行,而不是并发(并行)运行,从而违背了使进程异步的目的。
  • 如果需要运行脚本的多个实例,最好修改脚本以接受命令行上的数字参数:
    for ((i=114;i<=255;i++)); do python DoMyScript.py --number="$i" & done
    
    并删除该文件。
  • 如果无法更改脚本,则此解决方案应该有效:
    for i in {114..125}; do ( subdir="dir.$i" && mkdir "$subdir" && cd "$subdir" && 
              echo "$i" > numbers.txt && python ../DoMyScript.py; cd .. && rm -r "$subdir" ) & done
    
    这通过为每个脚本进程提供一个单独的numbers.txt运行目录来为每个脚本进程提供一个单独的文件。在子 shell 中创建和删除目录,并运行脚本。
    • 如果DoMyScript.py访问除相对路径名以外的任何文件numbers.txt ,则需要调整上述命令以适应这种情况。

    • 以上的灵感来自于格伦·杰克曼的回答 (虽然我相信我的会起作用,而他不会)。

    • 如果命令B取决于命令是否成功A,那么防御性编程比 更好。但这可能不是处理这种情况的理想方法。如果 失败,那么接下来的 111 次尝试也可能会失败,并且您将收到 112 条错误消息。如果发生致命错误,最好中止循环。A && BABmkdir dir.114

      该操作发生在异步子 shell 中这一事实使得这有些棘手。

      for i in {114..125}; do
              { subdir="dir.$i" && mkdir "$subdir" && echo "$i" > "$subdir"/numbers.txt; } || break;
              ( cd "$subdir" && python ../DoMyScript.py; cd .. && rm -r "$subdir" ) & done
      

      mkdir 如果一个或一个 命令失败,将导致循环中止 。echo value > file

    • 在“保证”可写的目录中工作可能会更好,例如 /tmp.但是,这会增加您的命令与其他进程发生冲突(干扰)的风险。

      • 您可以通过添加$$目录名称来缓解这​​种情况;例如, dir.$$.$i或者甚至 dir.$BASHPID
      • mkdir 这并不能消除由于文件系统已满而导致文件创建失败的风险 。
    • 请注意,即使脚本失败,上面的代码也会继续运行并删除临时目录。在这种情况下你可能想做点别的事情。

      • 哎呀。如果由于某种原因mkdir "$subdir"成功但cd "$subdir"失败了,这将继续执行cd .. && rm -r "$subdir"。如果有一个目录的名称类似于 dir.114您的父目录(即与当前目录平行),它将被删除。我相信您可以(至少在某种程度上)通过将最后一行更改为来解决此问题
        ( cd "$subdir" && { python ../DoMyScript.py; cd ..; } && rm -r "$subdir" ) & done
        
        或使用绝对路径;例如,subdir="$PWD/dir.$i"

相关内容