在bash“for $ in list”构造中一次取两个

时间:2014-01-21 11:06:52

标签: bash for-loop

我有一个文件列表,其中两个后续的文件总是在一起。我想在每次迭代时从for list中提取一个for循环提取两个文件,然后一次处理这两个文件(举个例子,让我们说我想要连接,即cat这两个文件)。

在一个简单的例子中,我的文件列表如下:

FILES="file1_mateA.txt file1_mateB.txt file2_mateA.txt file2_mateB.txt"

我可以破解它并说出

FILES="file1 file2"
for file in $FILES
do
    actual_mateA=${file}_mateA.txt
    actual_mateB=${file}_mateB.txt

    cat $actual_mateA $actual_mateB
done

但我希望能够处理配对A和配偶B具有任意名称的列表,例如:

FILES="first_file_first_mate.txt first_file_second_mate.txt file2_mate1.txt file2_mate2.txt"

有没有办法从每次迭代的$ FILES中提取两个值?

7 个答案:

答案 0 :(得分:21)

使用数组作为列表:

files=(fileA1 fileA2 fileB1 fileB2)
for (( i=0; i<${#files[@]} ; i+=2 )) ; do
    echo "${files[i]}" "${files[i+1]}"
done

答案 1 :(得分:8)

您可以使用xargs(1),例如

ls -1 *.txt | xargs -n2 COMMAND 

开关-n2让xargs从管道输出中选择2个连续的文件名来传递命令

成对连接10个文件file01.txt ... file10.txt 可以使用

ls *.txt | xargs -n2 sh -c 'cat $@  > $1.$2.joined' dummy

获取5个结果文件

file01.txt.file02.txt.joined
file03.txt.file04.txt.joined
file05.txt.file06.txt.joined
file07.txt.file08.txt.joined
file09.txt.file10.txt.joined

请参阅'info xargs'以获取解释。

答案 2 :(得分:2)

您可以从while循环中读取值,并使用xargs将每个读取操作限制为两个标记。

files="filaA1 fileA2 fileB1 fileB2"
while read a b; do
    echo $a $b
done < <(echo $files | xargs -n2)

答案 3 :(得分:1)

这个怎么样:

park=''
for file in $files  # wherever you get them from, maybe $(ls) or whatever
do
  if [ "$park" = '' ]
  then
    park=$file
  else
    process "$park" "$file"
    park=''
  fi
done

在每次奇数迭代中,它只存储值(在park中),然后在每次偶数迭代中使用存储的和当前值。

答案 4 :(得分:1)

您可以将字符串转换为数组,并按元素读取此新数组:

#!/bin/bash

string="first_file_first_mate.txt first_file_second_mate.txt file2_mate1.txt file2_mate2.txt"
array=(${string})
size=${#array[*]}

idx=0

while [ "$idx" -lt "$size" ]
do
    echo ${array[$idx]}
    echo ${array[$(($idx+1))]}
    let "idx=$idx+2"
done

如果您的字符串中的分隔符与空格不同(即;),则可以使用以下转换为数组:

array=(${string//;/ })

答案 5 :(得分:0)

您可以尝试这样的事情:

echo file1 file2 file3 file4 | while read -d ' ' a; do read -d ' ' b; echo $a $b; done
file1 file2
file3 file4

或者这个,有点麻烦的技术:

echo file1 file2 file3 file4 |tr " " "\n" | while :;do read a || break; read b || break; echo $a $b; done 
file1 file2
file3 file4

答案 6 :(得分:0)

似乎awk适合

的其中一件事
$ awk '{for (i = 1; i <= NF; i+=2) if( i+1 <= NF ) print $i " " $(i+1) }' <<< "$FILES"
file1_mateA.txt file1_mateB.txt
file2_mateA.txt file2_mateB.txt

然后你可以通过设置IFS = $'\ n'

来循环它

e.g。

#!/bin/bash

FILES="file1_mateA.txt file1_mateB.txt file2_mateA.txt file2_mateB.txt file3_mat
input=$(awk '{for (i = 1; i <= NF; i+=2) if( i+1 <= NF ) print $i " " $(i+1) }' 

IFS=$'\n'
for set in $input; do
  cat "$set" # or something
done

将尝试做什么

$ cat file1_mateA.txt file1_mateB.txt
$ cat file2_mateA.txt file2_mateB.txt

在没有匹配的情况下忽略奇怪的情况。