У меня есть текстовый файл:
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
Это работает, но это очень сложно и требует много времени для обработки длинных текстовых файлов.
Есть способ сделать это попроще?
Ответы:
iirc:
cat filename.txt | awk '{ print $2 $4 }'
или, как указано в комментариях:
awk '{ print $2 $4 }' filename.txt
источник
awk '{print $2,$4}' filename.txt
лучше (нет трубы, вызывается только одна программа)cat
в своих сценариях bash вместо указания имени файла, потому что накладные расходы минимальны и потому что синтаксисcat ... | ... > ...
действительно хорошо показывает, что такое ввод и куда идет вывод. Но вы правы, здесь это на самом деле не нужно.< input awk '{ print $2 $4 }' > output
для этого.Вы можете использовать
cut
команду:cut -d' ' -f3,5 < datafile.txt
печатает
то
-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
источник
Для полноты:
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
источник
Еще один простой вариант -
$ while read line do set $line # assigns words in line to positional parameters echo "$3 $5" done < file
источник
Если ваш файл содержит 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
Если вы используете структурированные данные, это дает дополнительное преимущество, заключающееся в том, что вы не запускаете дополнительный процесс оболочки
tr
и /cut
или что-то еще. ...(Конечно, вы захотите защититься от неправильных входных данных с помощью условных выражений и разумных альтернатив.)
... while read line ; do lineCols=( $line ) ; echo "${lineCols[0]}" echo "${lineCols[1]}" done < $myFQFileToRead ; ...
источник