如何循环处理两个输入文件

如何循环处理两个输入文件

我使用 awk 来匹配两个文件,然后将 file2 和 file1 的元素相乘。

 awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
      /:/ || !NF{print; next}
     {print $1, $2*a[$1], $2*b[$1]}' file2 file1 > output

该脚本仅处理两个输入文件并生成一个输出文件。

我想做一个循环来将此脚本用于许多(数千个)文件。我尝试这样做:

for file1 in ../mo/*e.log | 
for file2 in ../excited/*-d.log;   do
awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
     /:/ || !NF{print; next}
     {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
done

这些文件是相关的,因此类似于 0001e.log 和 0001-d.log、0002e.log 和 0002-d.log、0002e.log 和 0002-d.log ... 预期输出可能是 0001f.log 、 0002f .log , 0003f.log ...

但没有成功。有任何想法吗?

答案1

也许你想要:

set ../mo/*e.log
for file2 in ../excited/*-d.log; do
  file1=$1; shift
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
       /:/ || !NF{print; next}
       {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
done

或者与zsh

file1s=(../mo/*e.log)
file2s=(../excited/*-d.log)
for file1 file2 (${file1s:^file2s}) {
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
       /:/ || !NF{print; next}
       {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
}

上面,我们有两个排序的文件名列表,并且我们并行地浏览这两个列表。如果要匹配inmo和 in文件的基本名称,您可以这样做:excited

for file1 in ../mo/*e.log; do
  basename=${file1%e.log}
  basename=${basename##*/}
  file2=../excited/$basename-d.log
  [ -f "$file2" ] || continue
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
       /:/ || !NF{print; next}
       {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
done

答案2

尝试paste file1 file2 | tr '\t' '*' | bc > output

然后对于大循环(与巴什),它将文件从../莫/,../兴奋的/,并将产品输出到F当前目录中的一系列编号文件:

for f in ../mo/*e.log; do
    g=${f/mo/excited}
    o=${f##*/}
    paste $f ${g/e.log/-d.log} | tr '\t' '*' | bc > ${o/e.log/f.log} 
done

演示,(与巴什isms),打印 1-5 的平方:

paste <(seq 5) <(seq 5) | tr '\t' '*' | bc

输出:

1
4
9
16
25

答案3

如果您安装了 GNU Parallel,您可以执行以下操作:

doit() {
  file1="$1"
  file2="$2"
  output="$3"
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
      /:/ || !NF{print; next}
     {print $1, $2*a[$1], $2*b[$1]}' "$file2" "$file1" > "$output"
}
export -f doit

# If all filenames fit on a command line:
parallel --xapply doit {1} {2} {1/.}{2/.}.out ::: ../mo/?*e.log ::: ../excited/?*d.log
# With newer versions you can do:
parallel  doit {1} {2} {1/.}{2/.}.out ::: ../mo/?*e.log :::+ ../excited/?*d.log

# If you do not like the {/.} you can do:
parallel doit {1} '{= s/e.log/d.log/;s:/mo/:/excited/:; =}' '{=s/.log/.out/;s:^../mo/::;=}' ::: ../mo/?*e.log

# If all the files do not fit on the command line (because you have thousands):
finda() { find ../mo/ -name '*e.log'; }
findb() { find ../excited/ -name '*d.log'; }

parallel --xapply doit {1} {2} {1/.}{2/.}.out :::: <(finda) <(findb)
parallel doit {1} {2} {1/.}{2/.}.out :::: <(finda) ::::+ <(findb)
finda | parallel doit {1} '{= s/e.log/d.log/;s:/mo/:/excited/:; =}' '{=s/.log/.out/;s:^../mo/::;=}'

每个核心将运行一项作业。如果您更喜欢一次只做一项工作,请替换parallelparallel -j1.

GNU Parallel 是一个通用并行器,可以轻松地在同一台计算机或多台您可以通过 ssh 访问的计算机上并行运行作业。它通常可以代替for循环。

如果您想要在 4 个 CPU 上运行 32 个不同的作业,则并行化的直接方法是在每个 CPU 上运行 8 个作业:

简单的调度

相反,GNU Parallel 在完成后会生成一个新进程 - 保持 CPU 处于活动状态,从而节省时间:

GNU 并行调度

安装

如果您的发行版未打包 GNU Parallel,您可以进行个人安装,不需要 root 访问权限。这样做可以在 10 秒内完成:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README

了解更多

查看更多示例:http://www.gnu.org/software/parallel/man.html

观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

浏览本教程:http://www.gnu.org/software/parallel/parallel_tutorial.html

注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel

相关内容