从bash循环中的.dat文件中选择多个列并水平合并它们

时间:2017-06-07 23:24:33

标签: bash

我几乎是这方面的初学者,并且在处理.dat文件时遇到了麻烦。我有很多.dat文件(a_“number”_b.dat),每个包含4列,我想通过for循环从每个列中抽出第2列和第4列,并将它们水平合并到一个新文件中,即挑出列每个循环并将它们并排添加到文件中。我尝试使用awk | paste语句和cut | paste语句,但根本没有使用它。在awk的情况下,我最终得到的文件只包含在循环中读取的最后一个文件中的第2列和第4列,并且剪切|粘贴给了我一个空白文件。这是我使用的代码:

phpinfo()

输入和输出示例:

for k in {1..9}
do
awk '{print $2,$4}' a_0"$k"_b.dat > atest.dat
paste atest.dat atestf.dat > atestf.dat
#cut -f2 a_0"$k"_b.dat | paste atest.dat
#cut -f4 a_0"$k"_b.dat | paste atest.dat
done
编辑:我忘了提到一些文件底部缺少行,而且当并排放置列时我不得不将它们留作空格。

2 个答案:

答案 0 :(得分:0)

这个似乎工作正常:

for ((k=1;k<=2;k++));do
tmp="$(cat mergefile)"
paste -d ' ' <(echo "$tmp") <(cut -d ' ' -f2,4 "file$k")  > mergefile
done
cat mergefile
#Output
 10 1000 50 5000                                                                                                                                                                
 20 2000 60 6000                                                                                                                                                                
 30 3000 70 7000                                                                                                                                                                
 40 4000 80 8000 

Cut default delimiter is tab,您需要明确指定空格作为分隔符。

同样适用于粘贴。

您无法打开文件进行阅读,也无法在同一时间进行书写。 因此,您的初始尝试paste atest.dat atestf.dat > atestf.dat失败,因为文件atestf.dat被打开以供过去阅读,甚至用于使用&gt;进行书写。 (输出重定向)。这就是我使用tmp变量加载我的解决方案中mergefile中已存在的数据的原因。

答案 1 :(得分:0)

解决方案

输入

  a_1_b.dat        a_2_b.dat
      |                |
      V                V

1 10 100 1000    5 50 500 5000
2 20 200 2000    6 60 600 6000
3 30 300 3000    7 70 700 7000
4 40 400 4000    8 80 800 8000

脚本

# script.sh
dat_files=( $(find -E . -type f -maxdepth 1 -regex '^.*\/a_[0-9]+_b\.dat$') )

for line_number in $(seq 1 $(wc -l < ${dat_files[0]}))
do
  for file in ${dat_files[@]}
  do
    awk -v l=$line_number 'BEGIN {ORS=" "} NR==l {print $2, $4}' "$file"
  done
  echo
done

脚本说明

dat_files=...行将所有匹配的文件存储到一个数组中。数组中的所有文件都符合以下条件......

  • 常规文件(-type f
  • 文件名与正则表达式模式匹配^.*\/a_[0-9]+_b\.dat$
    • ^.*\/a_) - 以a_
    • 开头
    • [0-9]+) - 后跟一个或多个数字
    • _b) - 后跟_b
    • \.dat) - 以.dat
    • 结尾

外部for循环从1迭代到第一个匹配文件(wc -l)中的行数(${dat_files[0]})。这假设所有文件具有相同的行数。因此,如果文件有20行,则外循环从1迭代到20

内部for循环迭代所有匹配的文件并输出字段/列2和4,在每行的末尾添加一个空格而不是每次迭代的换行符(OFS=' ')。这样下一个文件的字段2和4(下一次迭代)就在前面字段的右边而不是在它们下面。

这就是它的全部!

命令

./script.sh > result.txt

输出

10 1000 50 5000 
20 2000 60 6000 
30 3000 70 7000 
40 4000 80 8000