在文本文件中获取第n列


86

我有一个文本文件:

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

它可以工作,但是非常复杂,并且需要很长时间来处理长文本文件。

有没有更简单的方法可以做到这一点?


1
每行的第二个单词简单地称为第二列!
伯纳德2014年

Answers:


127

iirc:

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

或者,如评论中所述:

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

16
UUOC !!!awk '{print $2,$4}' filename.txt更好(没有管道,只有一个程序被调用)
蓝色

5
我经常cat在bash脚本中使用@blue而不是指定文件名,因为开销很小,并且因为语法cat ... | ... > ...确实很好地显示了输入内容和输出位置。没错,这里实际上并不需要它。
Tom van der Woerdt 2013年

8
@TomvanderWoerdt:我有时< input awk '{ print $2 $4 }' > output为此目的而写。
ruakh 2013年

69

您可以使用以下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列

cut要快得多对于大文件作为一个纯粹的外壳解决方案。如果文件由多个空格分隔,则可以先将其删除,例如:

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

其中(gnu)sed将用单个替换任何tabspace字符space

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

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

1
效果很好...如果您能保证每行上都有
足够

24

为了完整性:

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

美观,易读,并且不需要perls / awks / others,它们全部由内建在一个shell中。
Petr Matousu19年

6

另一种简单的变体-

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

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)。


会更喜欢readcut因为它对字段之间的多个空格具有鲁棒性,并且您不需要数组魔术:while read word1 word2 word3 word4 rest; do doSomethingWith $word2 $word4; done
user829755 2013年

3

如果您使用的是结构化数据,则具有不调用额外的Shell进程来运行tr和/或执行其他操作的好处cut。...

(当然,您将希望通过条件和合理的选择来防止输入错误。)

...
while read line ; 
do 
    lineCols=( $line ) ;
    echo "${lineCols[0]}"
    echo "${lineCols[1]}"
done < $myFQFileToRead ; 
...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.