我需要以正确的顺序向程序提供一些特定的文件,并两两分组。
如果我有
A_file.txt
B_file.txt
C_file.txt
D_file.txt
我需要将其提供给程序,以便首先处理文件 A 和 B,然后处理 C 和 D,依此类推。在本质上:
for i in *.txt; do
some_program A_file.txt B_file.txt > output_AB
some_program C_file.txt D_file.txt > output_CD
我知道上面说的没有道理,但只是为了说明这一点。本质上,迭代.txt
文件夹中的所有文件,但一次将两个文件提供给程序,然后移至下两个文件。
正在学习,非常感谢。
答案1
#!/bin/sh
set -- *_file.txt
until [ "$#" -lt 2 ]; do
process "$1" "$2" >"output_${1%_file.txt}${2%_file.txt}"
shift 2
done
这将根据与问题中的名称匹配的文件名通配模式将位置参数设置为您感兴趣的文件名列表。然后,它使用循环迭代此列表,直到列表中剩余的名称少于两个($#
是位置参数列表的长度)。
在每次迭代中,都会处理列表的前两个元素$1
和$2
,然后使用 移出列表shift 2
。
处理的输出被重定向到一个名为 的文件,output_
后跟两个文件名的可变部分的串联(无论_file.txt
每个文件中的静态字符串之前是什么)。
这假设文件的命名方式是按字典顺序对名称进行排序(通配模式的扩展将执行此操作)会产生可以按照问题中所示的方式配对的名称列表。
答案2
你可以用xargs
命令来做到这一点。如果我有这些文件:
$ ls
A_file.txt B_file.txt C_file.txt D_file.txt E_file.txt F_file.txt G_file.txt H_file.txt
然后我可以像这样同时处理这两个:
$ find . -type f | xargs -n2 echo some_program
some_program ./A_file.txt ./B_file.txt
some_program ./C_file.txt ./D_file.txt
some_program ./E_file.txt ./F_file.txt
some_program ./G_file.txt ./H_file.txt
在这里我只是简单地调用echo
,但您当然可以放弃echo
并实际运行some_program
。这将一次处理两个文件......但它不处理为每次调用生成输出文件名。
如果我们做得更详细一些,我们可以将其输出到以第一个输入文件名命名的文件:
find . -type f | xargs -n2 sh -c 'echo some_program $1 $2 > $1.output' --
A_file.txt.output
这将为A_file.txt
和B_file.txt
、C_File.txt.output
下一对生成文件,依此类推。您可以通过应用各种转换来更喜欢输出文件名;例如,要获取您在问题中要求的文件名,您可以编写:
find . -type f | xargs -n2 sh -c 'echo some_program $1 $2 > output_${1:2:1}${2:2:1}' --
这将生成输出文件名output_AB
,output_CD
等等。
答案3
如果可以选择从 bash 切换到 zsh,那么只需:
for i j ( *.txt(N) ) some_program -- $i $j > output_$i[1]$j[1]
(N)
启用该 glob 扩展中的 nullglob,以便在没有匹配项时不会报告错误。
如果文件数量为奇数,则最后一次运行时将设置$j
为空字符串。当我们在参数 to 中不加引号时some_program
,将导致没有相应的参数传递给它。"$j"
如果您希望在这种情况下将空参数传递给它,请替换为。
扩展*.txt
将按字母顺序排列;您可以使用o
,O
和/或将顺序更改为您想要的任何内容n
全局限定符。
对于每次迭代时的任意数量的文件而不是 2 个:
files=( *.txt(N) ) n=5
while (( $#files )) {
some_program -- $files[1,n] > output_${(Mj[])files[1,n]#?}
files[1,5]=()
}
或者使用zargs
:
autoload -Uz zargs
process() some_program -- $@ > output_${(Mj[])@#?}
zargs -rl5 -- *.txt(N) -- process
在 中${(Mj[])array#?}
,${array#?}
将从数组的每个元素中去除前导字符,但在 中,则返回附加的M
内容。M
结果j
没有任何内容 ( []
),因此您将得到一个由每个元素的第一个字符组成的字符串。
答案4
将文件列表转储到数组中并从中读取。
#!/bin/bash
arr=( *.txt )
i=0
while [ $i -lt ${#arr[@]} ];
do
echo ${arr[$i]} ${arr[ $[$i+1] ]}
i=$[$i+2]
done
如果您有奇数个文件,该请求${arr[ $[$i+1] ]}
将默默地为您提供一个空字符串。在这种情况下该怎么做由您决定。