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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21256334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 09:19:25  来源:igfitidea点击:

Take two at a time in a bash "for file in $list" construct

bashfor-loop

提问by Alexander Engelhardt

I have a list of files where two subsequent ones always belong together. I would like a for loop extract two files out of this list per iteration, and then work on these two files at a time (for an example, let's say I want to just concatenate, i.e. cat the two files).

我有一个文件列表,其中两个后续文件始终属于一起。我希望 for 循环每次迭代从这个列表中提取两个文件,然后一次处理这两个文件(例如,假设我只想连接,即 cat 这两个文件)。

In a simple case, my list of files is this:

在一个简单的情况下,我的文件列表是这样的:

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

I could hack around it and say

我可以绕过它说

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

    cat $actual_mateA $actual_mateB
done

But I would like to be able to handle lists where mate A and mate B have arbitrary names, e.g.:

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

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

Is there a way to extract two values out of $FILES per iteration?

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

回答by choroba

Use an array for the list:

使用数组作为列表:

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

回答by Fritz G. Mehner

You could use xargs(1), e.g.

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

ls -1 *.txt | xargs -n2 COMMAND 

The switch -n2 let xargs select 2 consecutive filenames from the pipe output which are handed down do the COMMAND

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

To concatenate the 10 files file01.txt ... file10.txt pairwise one can use

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

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

to get the 5 result files

获取 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

Please see 'info xargs' for an explantion.

请参阅“info xargs”以获得解释。

回答by Fish

You could read the values from a while loop and use xargs to restrict each read operation to two tokens.

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

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

回答by Alfe

How about this:

这个怎么样:

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

In each odd iteration it just stores the value (in park) and in each even iteration it then uses the stored and the current value.

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

回答by Michael

You can transform you string to array and read this new array by elements:

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

#!/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

If you have delimiter in string different from space (i.e. ;) you can use the following transformation to array:

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

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

回答by Reinstate Monica Please

Seems like one of those things awkis suited for

似乎其中一件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

You could then loop over it by setting IFS=$'\n'

然后你可以通过设置 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

Which will try to do

哪个会尝试做

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

And ignore the odd case without the match.

并忽略不匹配的奇数情况。

回答by Mark Setchell

You could try something like this:

你可以尝试这样的事情:

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

Or this, somewhat cumbersome technique:

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

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