如何在bash中为循环添加分组机制
我有一个for循环,它在文件列表中循环,在for循环中调用一个脚本,该脚本将这个文件名作为输入。 差不多如何在bash中为循环添加分组机制,bash,Bash,我有一个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
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