处理来自多个目录的文件对组

时间:2017-01-13 10:42:37

标签: arrays bash file-processing

我在vec temp = w * A; inplace_trans(A, "lowmem"); temp = temp * A; w -= temp; 中有一些.txt个文件:

dir1

以及file_name_FOO31101.txt file_name_FOO31102.txt file_name_FOO31103.txt file_name_FOO31104.txt 中的一些相关foo.txt文件:

dir2

我最终希望能够为一对文件调用一个程序,以便:

迭代1

file_name_FOO31101_foo.txt
file_name_FOO31102_foo.txt
file_name_FOO31103_foo.txt
file_name_FOO31104_foo.txt

迭代2

program_call \
    --txt file_name_FOO31101.txt,file_name_FOO31102.txt \
    --foo file_name_FOO31101_foo.txt,file_name_FOO31102_foo.txt \
    --bar file_name_FOO31101_bar.txt,file_name_FOO31102_bar.txt

即。
program_call \ --txt file_name_FOO31103.txt,file_name_FOO31104.txt \ --foo file_name_FOO31103_foo.txt,file_name_FOO31104_foo.txt \ --bar file_name_FOO31103_bar.txt,file_name_FOO31104_bar.txt
file_name_FOO31101.txt,file_name_FOO31102.txt

file_name_FOO31103.txt,file_name_FOO31104.txt

question I posted yesterday的回答让我开始:

file_name_FOO31102.txt,file_name_FOO31103.txt

然后(不知道更好的方法)我为#!/bin/bash txt_files=/path/to/txt foo_files=/path/to/foo/files set -- "$txt_files"/*.txt [[ -e $1 || -L $1 ]] || { echo "No .txt files found in $txt_files" >&2; exit 1; } # $# = number of command line arguments passed to the script while (( $# > 1 )); do stem=$(basename "${1}" ) output_base=$(echo $stem | cut -d '_' -f 1,2,3) # split on '_' and save ID echo "-> Processing pairs of txt files : $1,$2" # Add files to array txt1+=($1) txt2+=($2) shift; shift done (( $# )) && echo "Left over file $1 still exists" 中的foo文件重复相同的循环:

dir2

然后迭代其中一个数组(所有数组必须长度相同)并调用程序:

set -- "$foo_files"/*_foo.txt

[[ -e $1 || -L $1 ]] || { echo "No foo.txt files found in $foo_files" >&2; exit 1; }

# $# = number of command line arguments passed to the script
while (( $# > 1 )); do

  stem=$(basename "${1}" )
  output_base=$(echo $stem | cut -d '_' -f 1,2,3) # split on '_' and save ID

  # Add files to array
  foo1+=($1)
  foo2+=($2)

  echo "-> Processing pairs of foo.txt files : $1,$2"

  shift; shift

done

(( $# )) && echo "Left over file $1 still exists"

这似乎基本上有效,打印:

# Seeing as all arrays must be the same length, loop over one and print out corresponding values for others 
for ((i=0;i<${#txt1[@]};++i)); do
    printf "program_call --txt %s,%s --foo %s,%s\n" "${txt1[i]}" "${txt2[i]}" "${foo1[i]}" "${foo2[i]}" 
done

但是,我怀疑对所有不同的dirs使用相同的while循环是实现此结果的一种不好的方法,特别是如果我想在我的程序调用中调用添加更多选项(例如program_call --txt /path/to/txt/file_name_FOO31101.txt,/path/to/txt/file_name_FOO31102.txt --foo /path/to/foo/files/file_name_FOO31101_foo.txt,/path/to/foo/files/file_name_FOO31102_foo.txt program_call --txt /path/to/txt/file_name_FOO31103.txt,/path/to/txt/file_name_FOO31104.txt --foo /path/to/foo/files/file_name_FOO31103_foo.txt,/path/to/foo/files/file_name_FOO31104_foo.txt ...)

这是一种合理的解决方法吗?

1 个答案:

答案 0 :(得分:0)

你的直觉是正确的:有比bash循环和数组更快的方法。

这里是如何列出和排序两个目录中的文件:

find txt foo -type f -name "*.txt" | sort -t'/' -k2,2

输出:

txt/a_0001.txt
foo/a_0001_foo.txt
txt/a_0002.txt
foo/a_0002_foo.txt
txt/a_0003.txt
foo/a_0003_foo.txt
txt/a_0004.txt
foo/a_0004_foo.txt
...

接下来,假设任一目录中没有额外或丢失的文件,您可以使用awk获得4 /行:

find txt foo -type f -name "*.txt" | sort -t'/' -k2,2 |
  awk '{printf $1" "; if(NR%4==0)printf "\n"}'

输出:

txt/a_0001.txt foo/a_0001_foo.txt txt/a_0002.txt foo/a_0002_foo.txt 
txt/a_0003.txt foo/a_0003_foo.txt txt/a_0004.txt foo/a_0004_foo.txt 
txt/a_0005.txt foo/a_0005_foo.txt txt/a_0006.txt foo/a_0006_foo.txt 
...

接下来,您可以使用另一个awk重新排序它们并创建命令字符串:

find txt foo -type f -name "*.txt" | sort -t'/' -k2,2 |
  awk '{printf $1" "; if(NR%4==0)printf "\n"}' |
  awk '{print "program_call --txt "$1","$3" --foo "$2","$4}'

输出:

program_call --txt txt/a_0001.txt,txt/a_0002.txt --foo foo/a_0001_foo.txt,foo/a_0002_foo.txt
program_call --txt txt/a_0003.txt,txt/a_0004.txt --foo foo/a_0003_foo.txt,foo/a_0004_foo.txt
...

基准测试,使用fugu的代码与find|sort|awk|awk从2000个文件制作500个命令字符串:

bash loops & arrays    10.070s
find|sort|awk|awk       0.019s

超过500倍的速度:)

您还可以通过使用管道而不是循环来运行命令字符串来节省时间:

find txt foo -type f -name "*.txt" | ... | sh
通过管道命令而不是GNU parallel通常更多的时间:

find txt foo -type f -name "*.txt" | ... | parallel

(如果您的系统上尚未安装parallel,则可能需要安装。)