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