一次循环多个项目

时间:2014-09-12 18:06:58

标签: bash shell unix xargs

我们可以迭代一组项目,一次考虑一个,如下所示:

#!/bin/bash
for i in $( ls ); do
    echo item: $i
done

我们如何在类似的循环中一次处理多个项目?类似的东西:

#!/bin/bash
for i,j,k in $( ls ); do
    echo item i: $i
    echo item j: $j
    echo item k: $k
done

第二个shell脚本不正确,但应准确说明我想要实现的目标。

7 个答案:

答案 0 :(得分:4)

假设您没有太多多项(尽管shell应该能够。) 处理不少位置论点。

# Save the original positional arguments, if you need them
original_pp=( "$@" )
set -- *
while (( $# > 0 )); do
    i=$1 j=$2 k=$3     # Optional; you can use $1, $2, $3 directly
    ...
    shift 3 || shift $#   # In case there are fewer than 3 arguments left
done

# Restore positional arguments, if necessary/desired
set -- "${original_pp[@]}"

对于POSIX兼容性,请使用[ "$#" -gt 0 ]而不是((...))表达式。以POSIX兼容的方式保存和恢复所有位置参数没有简单的方法。 (除非有一个字符,否则您可以使用它将它们明确地连接成一个字符串。)

以下是jm666提到的子shell:

(
    set -- *
    while [ "$#" -gt 0 ]; do
        i=$1 j=$2 k=$3
        ...
        shift 3 || shift $#
    done
)

子shell退出后,您在子shell中设置的参数的任何更改都将丢失,但上述代码与POSIX兼容。

答案 1 :(得分:3)

如果文件名不包含空格:

find . -maxdepth 1 | xargs -L 3 | while read i j k; do
  echo item i: $i
  echo item j: $j
  echo item k: $k
done

修改

我删除了-print0-0

答案 2 :(得分:1)

要获得to get n items a time from the list,我认为您希望从数组中获取n个项目。

像这样使用:

n=3
arr=(a b c d e)

echo "${arr[@]:0:$n}"
a b c

答案 3 :(得分:1)

迟到的回答,我会以非壮观的方式做到这一点:),如:

while read -r -d $'\0' f1
do
        read -r -d $'\0' f2
        read -r -d $'\0' f3

        echo "==$f1==$f2==$f3=="

done < <(find test/ ... findargs... -print0)

答案 4 :(得分:0)

以下是典型编程方式的另一种解决方案 - &gt;

#!/bin/bash
shopt -s nullglob
arr=(*) #read the files/dirs in an array
total=${#arr[@]} #get the array size
count=0;
#loop it thru in multiples of three
while [ $count -lt $((total-2)) ]
do
        echo "i is ${arr[$count]}"
        echo "j is ${arr[$((count+1))]}"
        echo "k is ${arr[$((count+2))]}"
        count=$((count+3))
done
#print the remaining element(s)
rem=$((total%3));    
if [ $rem -eq 1 ];
then
        echo "i is ${arr[$total-1]}"
elif [ $rem -eq 2 ];
then
        echo "i is ${arr[$total-2]}"
        echo "j is ${arr[$total-1]}"
fi
echo "Done"

答案 5 :(得分:0)

如果你有GNU Parallel,你可以运行:

ls | parallel -N3 "echo item i: {1}; echo item j: {2}; echo item k: {3}"

所有新计算机都有多个内核,但大多数程序本质上是串行的,因此不会使用多个内核。但是,许多任务都非常可并行化:

  • 在许多文件上运行相同的程序
  • 为文件中的每一行运行相同的程序
  • 为文件中的每个块运行相同的程序

GNU Parallel是一个通用的并行程序,可以很容易地在同一台机器上或在你有ssh访问权限的多台机器上并行运行作业。

如果要在4个CPU上运行32个不同的作业,并行化的直接方法是在每个CPU上运行8个作业:

Simple scheduling

GNU Parallel会在完成后生成一个新进程 - 保持CPU处于活动状态,从而节省时间:

GNU Parallel scheduling

<强>安装

个人安装不需要root访问权限。这可以在10秒内完成:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

有关其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README

了解详情

查看更多示例:http://www.gnu.org/software/parallel/man.html

观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

完成教程:http://www.gnu.org/software/parallel/parallel_tutorial.html

注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel

答案 6 :(得分:-1)

您可以使用xargsawksedpaste重新构建输入。

job_select()
{
  ls
}

job_process()
{
  while read i j k; do
    printf 'item i: %s\nitem j: %s\nitem k: %s\n' "$i" "$j" "$k"
  done
}

job_restructure_xargs()
{
  xargs -L 3
}

job_rstructure_awk()
{
  awk '(NR % 3 == 1) { i = $0 } (NR % 3 == 2) { j = $0 } (NR % 3 == 0){ k = $0; print(i,j,k)}'
}

job_restructure_sed()
{
  sed -e 'N;N;s/\n/ /g'
}

job_restructure_paste()
{
  paste - - -
}

然后是任何组合

job_select | job_restructure_xargs | job_process
job_select | job_restructure_awk | job_process
job_select | job_restructure_sed | job_process
job_select | job_restructure_paste | job_process

做你想做的事。