Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在bash中为循环添加分组机制_Bash - Fatal编程技术网

如何在bash中为循环添加分组机制

如何在bash中为循环添加分组机制,bash,Bash,我有一个for循环,它在文件列表中循环,在for循环中调用一个脚本,该脚本将这个文件名作为输入。 差不多 for file in $(cat list_of_files) ; do script $file done _文件的文件列表_包含以下文件 file1 file2 file3 ... 因此,每次迭代都会处理一个文件 我必须设计一些类似的东西,循环所有文件,将它们分成3组,这样在一个循环中,脚本将被调用3次,而不是一个接一个,然后在第二个循环迭代中再次调用其他3次,依此类推 大

我有一个for循环,它在文件列表中循环,在for循环中调用一个脚本,该脚本将这个文件名作为输入。 差不多

for file in $(cat list_of_files) ; do
    script $file
done
_文件的文件列表_包含以下文件

file1
file2
file3
...
因此,每次迭代都会处理一个文件

我必须设计一些类似的东西,循环所有文件,将它们分成3组,这样在一个循环中,脚本将被调用3次,而不是一个接一个,然后在第二个循环迭代中再次调用其他3次,依此类推

大概

for file in $(cat list_of_files) ; do
     # do somekind of grouping here
     call one more loop to run the sript.sh 3 times, so something like
     for i=1 to 3 and then next iteration from 4 to 6 and so on..
     script.sh $file1
     script.sh $file2
     script.sh $file3
done

我目前正在为如何完成这个循环而挣扎,我被困在这里,想不出有效的方法。

如果不一定要混合脚本语言,就不应该混合脚本语言

你可以从这个开始

from os import listdir
from os.path import isfile, join

PATH_FILES = "/yourfolder"

def yourFunction(file_name):
    file_path = PATH_FILES + "/" + file_name
    print(file_path) #or do something else
    print(file_path) #or do something else
    print(file_path) #or do something else


file_names = [f for f in listdir(PATH_FILES) if isfile(join(PATH_FILES, f))]
for file_name in file_names:
     yourFunction(file_name)
换成。。。边读边读 这种类型的循环非常危险和/或不正确。它不能正确处理带有空格、星号或其他特殊字符的文件名。作为一般规则,避免使用美元中的x。。。循环。有关详细信息,请参阅:

. 一个更安全的选择是在阅读时使用,如:

while IFS= read -r file; do
    ...
done < <(cat list_of_files)
一次读3本 到目前为止,这些更改还没有回答您的核心问题,即如何一次对3个文件进行分组。切换到read实际上还有第二个目的。它使分组变得容易。诀窍是每次迭代调用read多次。这是一个简单的变化,而阅读;对…来说这并不容易。。。在

下面是它的样子:

while IFS= read -r file1 &&
      IFS= read -r file2 &&
      IFS= read -r file3
do
    script.sh "$file1"
    script.sh "$file2"
    script.sh "$file3"
done < list_of_files
并行运行脚本 如果我没有弄错您的问题,那么您也希望同时运行脚本,而不是一个接一个地连续运行脚本。如果是这样,方法是附加&,这将使它们在后台运行。然后调用wait阻塞,直到它们全部完成,然后再继续

while IFS= read -r file1; do
    IFS= read -r file2
    IFS= read -r file3

    script.sh "$file1" &
    [[ -n $file2 ]] && script.sh "$file2" &
    [[ -n $file3 ]] && script.sh "$file3" &
    wait
done < list_of_files

可以使用bash数组存储文件名,直到获得其中3个:

#!/bin/bash

files=()

while IFS= read -r f; do
    files+=( "$f" )
    (( ${#files[@]} < 3 )) && continue
    script.sh "${files[0]}"
    script.sh "${files[1]}"
    script.sh "${files[2]}"
    files=()
done < list_of_files
然而,我认为John Kugelman的答案是简单的,然后是更好的:它使用更少的bash特定功能,那么它就可以更容易地转换为POSIX版本。

怎么样

xargs -d $'\n' -L 1 -P 3 script.sh <list_of_files
-p3并行运行3个进程。由于-L 1,-d选项可确保输入行中的空格不被视为单独的参数。

如果mapfile aka readarray可用/可接受。bash4+是必需的

假设script.sh可以接受多个输入

#!/usr/bin/env bash

while mapfile -tn3 files && (( ${#files[*]} == 3 )); do
  script.sh "${files[@]}"
done < list_of_files
如果始终有3行,则do后面的主体将运行/执行。如果在文件结尾之前没有足够的行来满足3行的要求,只需删除

&& (( ${#files[*]} == 3 ))
从剧本中

或者一个接一个地手动执行,但在文件结束之前,应该有3行代码需要处理

#!/usr/bin/env bash

while mapfile -tn3 files && (( ${#files[*]} == 3 )); do
  script.sh "${file[0]}"
  script.sh "${file[1]}"
  script.sh "${file[2]}"
done < list_of_files

效果也不同:约翰库格曼的答案处理所有的文件。对于您的解决方案,例如,如果文件总数为2,则根本不调用script.sh。@user1934428。该案例的具体行为未在报告中给出Q@user1934428可以通过在循环后调用剩余数组元素的脚本来更正此问题。@prex:您应该将重要的部分写入问题中,即并行处理文件3到3,而不是写入注释中@约翰·库格曼谢谢你,这种方法很有效。一件小事,当第一次运行完成时,如何启动第四次运行,第二次运行完成后如何启动第五次运行,依此类推,同时仍并行运行3个进程。我正在尝试修改此代码,但由于&,当前脚本在第三个进程后退出。你能帮忙吗
#!/usr/bin/env bash

while mapfile -tn3 files && (( ${#files[*]} == 3 )); do
  script.sh "${files[@]}"
done < list_of_files
#!/usr/bin/env bash

while mapfile -tn3 files && (( ${#files[*]} == 3 )); do
  for file in "${files[@]}"; do
    script.sh "$file"
  done
done < list_of_files
&& (( ${#files[*]} == 3 ))
#!/usr/bin/env bash

while mapfile -tn3 files && (( ${#files[*]} == 3 )); do
  script.sh "${file[0]}"
  script.sh "${file[1]}"
  script.sh "${file[2]}"
done < list_of_files