С sed
вами можно сделать:
sed '24q;1,5d;12,18d' <infile >outfile
... Возможно, более эффективное решение может быть найдено с head
. Дон уже продемонстрировал, как это может работать очень хорошо, но я тоже с этим поиграл. Что-то, что вы могли бы сделать, чтобы справиться с этим конкретным случаем:
for n in 5 6 7 6
do head -n"$n" >&"$((1+n%2))"
done <infile >outfile 2>/dev/null
... который будет вызывать head
4 раза, записывая либо в, outfile
либо в /dev/null
зависимости от того, является ли значение этой итерации $n
четным или нечетным числом.
Для более общих случаев я собрал это вместе с некоторыми другими вещами, которые у меня уже были:
somehead()(
### call it like:
### somehead -[repeat] [-][numlines]* <infile >outfile
set -e -- "${1#-}" "$@" #-e for arg validation
r=; cd -- "${TMP:-/tmp}" #go to tmp
dd bs=4096 of="$$$$" <&4 2>&3 & #dd <in >tmpfile &bg
until [ -s "$$$$" ]; do :; done #wait while tmpfile empty
exec <"$$$$" 4<&-; rm "$$$$" #<tmpfile; rm tmpfile
[ "$3${1}0" -ne "$3${2#?}0" ] || #validate args - chk $1
shift "$(((r=-${1:--1})||1))"; shift #shift 1||2
while [ "$(((r+=(_n=1))-1))" -ne 0 ] && #while ! $rptmax &&
IFS= read -r l && # ! EOF &&
printf "%.$(($1>0?${#l}+1:0))s" "$l # ? printf do
"; do for n do [ "${n#-}" -gt 0 ] || exit #args all -[nums>0]
head "-n$((${n#-}-_n))" >&"$((n>(_n=0)?1:3))" #head -n?$1 >?[+-]
done; done #done and done
) 4<&0 3>/dev/null #4<for dd 3>for head
Это может сделать вашу вещь, как:
seq 100 | somehead -1 -5 6 -7 6
... который печатает ...
6
7
8
9
10
11
19
20
21
22
23
24
Он ожидает, что его первым аргументом будет число повторений с префиксом -
или, в случае неудачи, просто a -
. Если указан счетчик, он будет повторять шаблон линии, заданный в следующих аргументах, столько раз, сколько указано, и останавливается, как только это будет сделано.
Для каждого следующего аргумента он будет интерпретировать отрицательное целое число, чтобы указать количество строк, в которое следует записать, /dev/null
и положительное целое число, чтобы указать количество строк, в которое следует записать stdout
.
Таким образом, в приведенном выше примере он печатает первые 5 строк до /dev/null
, следующие 6 до stdout
, следующие 7 до /dev/null
снова и следующие 6 еще раз до stdout
. Достигнув последнего из его аргументов и полностью циклически -1
повторяя счетчик, он затем выходит. Если бы это был первый аргумент, -2
он бы повторил процесс еще раз или, если -
мог, так долго, как мог.
Для каждого цикла arg цикл while
обрабатывается один раз. В верхней части каждого цикла первая строка из stdin
читается в переменную оболочки $l
. Это необходимо, потому что while head </dev/null; do :; done
будет повторяться до бесконечности - head
указывает в своем возвращении, когда он достиг конца файла. Таким образом, проверка на EOF посвящена read
и printf
запишет $l
плюс новую строку, stdout
только если второй аргумент является положительным целым числом.
read
Проверка усложняет петлю немного , потому что сразу же после того, как другой цикл называется - for
цикл , который перебирает арг , 2-$#
как представлено в $n
каждой итерации родительского while
цикла. Это означает, что для каждой итерации первый аргумент должен быть уменьшен на единицу от значения, указанного в командной строке, но все остальные должны сохранять свои исходные значения, и поэтому значение $_n
маркера var вычитается из каждого, но только когда-либо содержит значение больше 0 для первого аргумента
Это составляет основной цикл функции, но основная часть кода находится вверху и предназначена для того, чтобы функция могла чисто буферизовать даже канал в качестве входных данных. Это работает, сначала вызывая фон dd
для копирования его в tmpfile на выходе с размерами блоков 4k за штуку. Затем функция устанавливает цикл удержания - который почти никогда не должен завершать даже один полный цикл - просто для того, чтобы гарантировать, что dd
была произведена хотя бы одна запись в файл, прежде чем функция затем заменит свой стандартный ввод дескриптором файла, связанным с tmpfile, и после этого сразу же отменяет связь файла сrm
, Это позволяет функции надежно обрабатывать поток, не требуя перехватов или других действий для очистки - как только функция освобождает свою заявку на fd, tmpfile перестанет существовать, поскольку ее единственная именованная ссылка файловой системы уже удалена.
head
иtail
? Если это так, то ваше решение - самое лучшее, что вы можете сделать. Если вам разрешено использовать другие программыsed
или выawk
можете использовать более приятные решения (например, с меньшим количеством вызовов процессов).