程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本?

开发过程中遇到如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本的问题如何解决?下面主要结合日常开发的经验,给出你关于如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本的解决方法建议,希望对你解决如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本有所启发或帮助;

我有一个循环遍历文件列表的 for 循环,在 for 循环中调用了一个脚本,该脚本将这个文件名作为输入。 类似的东西

for file in $(cat List_of_files) ; do
    script $file
done

文件 List_of_files 有类似的文件

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

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

解决方法

for ... in改为while read

for file in $(cat list_of_files)

这种循环方式非常危险和/或不正确。它不适用于带有空格、星号或其他特殊字符的文件名。作为一般规则,避免 for x in $(...) 循环。有关更多详细信息,请参阅:

@H_489_45@
  • Bash Pitfalls: for f in $(ls *.mp3)
  • 更安全的替代方法是将 while read 与 process substitution 一起使用,如下所示:

    while IFS= read -r file; do
        ...
    done < <(cat list_of_files)
    

    我承认这很丑陋,但它可以安全地处理特殊字符。它用空格分隔文件名,并且不会扩展 * globs。有关此操作的更多详细信息,请参阅:

    @H_489_45@
  • Unix.SE: Understanding “IFS= read -r line”。
  • 然后您可以删除 U@R_772_10288@ss Use of Cat 并改用简单的重定向:

    while IFS= read -r file; do
        ...
    done < list_of_files
    

    一次读 3 个

    到目前为止,这些更改还没有回答您的核心问题,即如何一次对 3 个文件进行分组。切换到 read 实际上还有第二个目的。它使分组变得容易。诀窍是每次迭代多次调用 read。这是 while read 的一个简单更改; for ... in 并不容易。

    这是它的样子:

    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
    

    这将调用 read 三次,一旦这三个都成功,它就会进入循环体。

    如果您总是有 3 个项目的倍数需要处理,它会很有效。如果没有,它会在最后搞砸并跳过最后一个或两个文件。如果这是一个问题,我们可以更新它以尝试处理这种情况。

    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"
    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
    
    ,

    怎么样

    xargs -d $'\n' -L 1 -P 3 script.sh <list_of_files
    

    -P 3 并行运行 3 个进程。每个都获得一行的输入(由于 -L 1),而 -d 选项确保输入行中的空格不被视为单独的参数。

    ,

    您可以使用 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 版本。

    ,

    如果你不是绝对必须,你不应该混合脚本语言

    你可以从那个开始

    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)
    
    ,

    如果 @H_952_5@mapfile 又名 readarray 可用/可接受。 (需要bash4+)

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

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

    否则循环遍历名为 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
    

    do 之后的正文如果总是有 3 行,就会运行/执行,如果直到文件末尾没有足够的行来满足 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
    

    大佬总结

    以上是大佬教程为你收集整理的如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本全部内容,希望文章能够帮你解决如何在bash中的for循环中添加分组机制 将for ... in改为while read一次读 3 个并行运行脚本所遇到的程序开发问题。

    如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

    本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
    如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。