Awk - вывести вторую строку из числа файлов .dat в один файл

9

У меня есть несколько файлов что-то вроде: (на самом деле у меня есть 80)

file1.dat

2 5

6 9

7 1

file2.dat

3 7

8 4

1 3

Я хочу в итоге файл, содержащий все вторые строки. т.е.

output.dat

6 9

8 4

То, что у меня есть, зацикливается на имена файлов, но затем перезаписывает файл перед ним. например, вывод вышеуказанных файлов будет просто

8 4

мой сценарий оболочки выглядит так:

post.sh

TEND = 80

TINDX = 0

while [ $TINDX - lt $TEND]; do

awk '{ print NR==2 "input-$TINDX.dat > output.dat

TINDX = $((TINDX+1))

done
Роланд
источник

Ответы:

17

Удалите whileцикл и используйте расширение скобки оболочки, а также FNRвстроенную awkпеременную:

awk 'FNR==2{print $0 > "output.dat"}' file{1..80}.dat
jimmij
источник
9
еще корочеawk 'FNR==2' file{1..80}.dat > output.dat
Archemar
7

Как насчет ... head -n 2 input.dat | tail -n 1 | awk...

HarveyP
источник
Да, head/ tailэто определенно вариант, вам не нужно awkтогда.
Джимми
7

sed будет достаточно:

sed -sn 2p file{1..80}.dat > output.dat

-s Опция необходима для печати 2-й строки из каждого файла, в противном случае будет напечатана только 2-я строка первого файла.

aragaer
источник
2

Решение от aragaer самое хорошее sed, да. Но так как мне очень нравится head|tailрезать, у меня есть head|tailрешение, которое поддерживает несколько файлов, а не один input.dat. Использование цикла for вместо передачи списка файлов в sed также упрощает другие действия с файлом до / после извлечения второй строки с помощью sed.

# empty output.dat first
rm output.dat

# have a one-liner
for file in *.dat; do head -2 $file | tail -1 >> output.dat; done 

Многострочная версия с большим количеством комментариев:

NB: код ниже будет работать. Мы свободны поставить разрыв строки после |, &&или ||, и продолжить нашу команду на следующей строке; мы можем даже поместить комментарии между ними. Я провел годы, не зная этого (и не видя этого нигде). Этот стиль менее полезен в интерактивном режиме, но очищает файлы сценариев без конца.

# empty output.dat first
rm output.dat

for file in *.dat; do
    # file -> lines 1 and 2 of file
    head -2 $file |
    # lines 1 and 2 of file -> line 2 of file >> appended to output.dat
    tail -1 >> output.dat
done
Esteis
источник
0

Очевидно, есть много способов сделать это - я думаю, мне больше всего нравится ответ @ aragaer's sed .

Вот тот, который использует чисто встроенные bash и не нуждается в форке каких-либо внешних утилит:

for f in file{1..80}.dat; do
    { read && read && printf "%s\n" "$REPLY"; } < "$f"
done > output.dat
Цифровая травма
источник
0

Для эффективности использования awkи sedв ответах здесь на нескольких файлах лучше использовать nextfileоператор для пропуска обработки нежелательных строк в awk.

awk 'FNR==2{ print >"output.dat"; nextfile}' infile{1..80}.dat

и с помощью sedмы можем выйти при обработке на 3- й строке и sedобработать следующий файл.

sed -sn '2p;3q' infile{1..80}.dat > output.dat
αғsнιη
источник