在文本文件中取第n列

时间:2013-06-16 20:15:10

标签: linux bash

我有一个文本文件:

1 Q0 1657 1 19.6117 Exp
1 Q0 1410 2 18.8302 Exp
2 Q0 3078 1 18.6695 Exp
2 Q0 2434 2 14.0508 Exp
2 Q0 3129 3 13.5495 Exp

我想把每一行的第二和第四个单词都这样:

1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

我正在使用此代码:

 nol=$(cat "/path/of/my/text" | wc -l)
 x=1
 while  [ $x -le "$nol" ]
 do
     line=($(sed -n "$x"p /path/of/my/text)
     echo ""${line[1]}" "${line[3]}""  >> out.txt
     x=$(( $x + 1 ))
 done

它有效,但它非常复杂,需要很长时间才能处理长文本文件。

有更简单的方法吗?

6 个答案:

答案 0 :(得分:101)

iirc:

cat filename.txt | awk '{ print $2 $4 }'

或者,如评论中所述:

awk '{ print $2 $4 }' filename.txt

答案 1 :(得分:53)

您可以使用cut命令:

cut -d' ' -f3,5 < datafile.txt

打印

1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

  • -d' ' - 意思是,使用space作为分隔符
  • -f3,5 - 拍摄并打印第3和第5列

对于作为纯shell解决方案的大型文件,cut 更快。如果您的文件使用多个空格分隔,则可以先删除它们,例如:

sed 's/[\t ][\t ]*/ /g' < datafile.txt | cut -d' ' -f3,5

其中(gnu)sed将使用单个tab替换所有spacespace个字符。

对于变体 - 这里也是一个perl解决方案:

perl -lanE 'say "$F[2] $F[4]"' < datafile.txt

答案 2 :(得分:21)

为了完整起见:

while read _ _ one _ two _; do
    echo "$one $two"
done < file.txt

也可以使用任意变量(例如_)代替junk。关键是要提取列。

演示:

$ while read _ _ one _ two _; do echo "$one $two"; done < /tmp/file.txt
1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

答案 3 :(得分:6)

一个更简单的变体 -

$ while read line
  do
      set $line          # assigns words in line to positional parameters
      echo "$3 $5"
  done < file

答案 4 :(得分:4)

如果您的文件包含 n 行,那么您的脚本必须读取文件 n 次;因此,如果你将文件的长度加倍,你的脚本工作量就会翻两番 - 而且几乎所有的工作都被丢弃了,因为你要做的就是按顺序循环遍历。

相反,循环文件行的最佳方法是使用while循环,条件命令为read内置:

while IFS= read -r line ; do
    # $line is a single line of the file, as a single string
    : ... commands that use $line ...
done < input_file.txt

在你的情况下,既然你想把这行拆分成一个数组,并且read内置实际上对填充一个数组变量有特别的支持,你可以这样写:

while read -r -a line ; do
    echo ""${line[1]}" "${line[3]}"" >> out.txt
done < /path/of/my/text

或更好:

while read -r -a line ; do
    echo "${line[1]} ${line[3]}"
done < /path/of/my/text > out.txt

但是,对于您正在做的事情,您可以使用cut实用程序:

cut -d' ' -f2,4 < /path/of/my/text > out.txt

(或awk,如Tom van der Woerdt所建议,或perl,甚至sed)。

答案 5 :(得分:3)

如果您正在使用结构化数据,这还有一个额外的好处,即不调用额外的shell进程来运行tr和/或cut或其他东西。 ...

(当然,你会想要用条件和理智的替代方案来防范糟糕的输入。)

...
while read line ; 
do 
    lineCols=( $line ) ;
    echo "${lineCols[0]}"
    echo "${lineCols[1]}"
done < $myFQFileToRead ; 
...