Візьміть 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

Я хочу взяти 2-е і 4-е слово кожного рядка так:

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
2-е слово кожного рядка просто називається 2-м стовпцем!
Бернард,

Відповіді:


127

iirc:

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

або, як зазначено в коментарях:

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

16
УУПЦ !!! awk '{print $2,$4}' filename.txtкраще (немає каналу, лише одна програма називається)
синій

5
@blue, який я часто використовую catу своїх скриптах bash, замість того, щоб вказувати ім'я файлу, оскільки накладні витрати мінімальні і тому, що синтаксис cat ... | ... > ...дуже добре показує, що таке вхідні дані і куди йде вихідний результат. Ти прав, правда, насправді тут це не потрібно.
Том ван дер Вердт,

8
@TomvanderWoerdt: Іноді я пишу < input awk '{ print $2 $4 }' > outputз цією метою.
ruahh

69

Ви можете використовувати cutкоманду:

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

відбитки

1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

the

  • -d' '- означає, використовувати spaceяк роздільник
  • -f3,5 - візьміть і роздрукуйте 3 і 5 колонку

cutЦе набагато швидше для великих файлів в якості чистого розчину оболонки. Якщо ваш файл розділений кількома пробілами, ви можете спочатку їх видалити, наприклад:

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

де (gnu) sed замінить будь-який tabабо spaceсимволи на один space.

Для варіанту - ось також рішення для perl:

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

1
Добре працює ... якщо вам гарантована така кількість пробілів у кожному рядку, точно ... :)
rogerdpack

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 / AWK / інші, все в одній оболонці від вбудованих.
Petr Matousu,

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, як пропонує Том ван дер Вердт, або perl, або навіть sed).


воліли б readбільш , cutтому що це міцний проти кількох просторів між полями і вам не потрібно диво масиву:while read word1 word2 word3 word4 rest; do doSomethingWith $word2 $word4; done
user829755

3

Якщо ви використовуєте структуровані дані, це має додаткову перевагу, якщо не викликати зайвий процес оболонки для запуску trта / cutабо щось інше. ...

(Звичайно, ви хочете захиститися від поганих входів за допомогою умовних та розумних альтернатив.)

...
while read line ; 
do 
    lineCols=( $line ) ;
    echo "${lineCols[0]}"
    echo "${lineCols[1]}"
done < $myFQFileToRead ; 
...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.