Подтвердить что ты не робот

Возьмите n-ную колонку в текстовом файле

У меня есть текстовый файл:

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

Это работает, но это очень сложно и занимает много времени для обработки длинных текстовых файлов.

Есть ли более простой способ сделать это?

4b9b3361

Ответ 1

iirc:

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

или, как указано в комментариях:

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

Ответ 2

Вы можете использовать команду 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 заменит любые символы tab или space одним space.

Для варианта - это тоже решение perl:

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

Ответ 3

Для полноты:

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

Ответ 4

Еще один простой вариант -

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

Ответ 5

Если ваш файл содержит n строк, ваш script должен прочитать файл n раз; поэтому, если вы удваиваете длину файла, вы в четыре раза увеличиваете объем работы, которую выполняет ваш script — и почти вся эта работа просто отбрасывается, так как все, что вы хотите сделать, это цикл по строкам по порядку.

Вместо этого наилучшим способом петли над строками файла является использование цикла while, при этом команда condition является read builtin:

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

Ответ 6

Если вы используете структурированные данные, это имеет дополнительное преимущество, не вызывая дополнительный процесс оболочки для запуска tr и/или cut или что-то еще....

(Конечно, вы захотите защитить от плохих входов с условностями и разумными альтернативами.)

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