Так что это для домашней работы, но я не буду задавать конкретный домашний вопрос.
Мне нужно использовать голову и хвост, чтобы получить разные наборы строк из одного файла. Как строки 6-11 и строки 19-24 и сохраните их в другой файл. Я знаю, что могу сделать это с помощью дополнения, таких как
head -11 file|tail -6 > file1; head -24 file| tail -6 >> file1.
Но я не думаю, что мы должны.
Есть ли конкретный способ, которым я мог бы объединить команды head и tail и затем сохранить в файл?
head
иtail
? Если это так, то ваше решение - самое лучшее, что вы можете сделать. Если вам разрешено использовать другие программыsed
или выawk
можете использовать более приятные решения (например, с меньшим количеством вызовов процессов).>>
) приложив две команды в скобках , чтобы перенаправить их каскадный выход:(head -11 file | tail -6; head -24 file | tail -6) > file1
. Это действительно сводится к личным предпочтениям, которые приятнее.Ответы:
Вы можете сделать это с помощью
head
одной и основной арифметики, если вы группируете команды с{ ... ; }
использованием такой конструкции, какгде все команды имеют одинаковый ввод (спасибо @mikeserv ).
Получение строк 6-11 и строк 19-24 эквивалентно:
Итак, в основном вы бы запустили:
источник
Вы можете использовать
{ … }
конструкцию группировки, чтобы применить оператор перенаправления к составной команде.Вместо дублирования первых M + N строк и сохранения только последних N, вы можете пропустить первые M строк и продублировать следующие N. Это значительно быстрее для больших файлов . Помните, что
+N
аргументtail
- это не количество пропускаемых строк, а еще один плюс - номер первой строки для печати со строками, пронумерованными от 1.В любом случае, выходной файл открывается только один раз, но входной файл просматривается один раз для извлечения каждого фрагмента. Как насчет группировки входов?
В общем, это не работает. (Это может работать в некоторых системах, по крайней мере, когда ввод является обычным файлом.) Почему? Из-за входной буферизации . Большинство программ, в том числе
tail
, не читают свои входные байты за байтом, но несколько килобайт за раз, потому что это быстрее. Таким образом,tail
читает несколько килобайт, пропускает немного в начале, передает немного большеhead
и останавливается - но то, что читается, читается и не доступно для следующей команды.Другой подход заключается в использовании
head
piped/dev/null
для пропуска строк.Опять же, это не гарантирует работу из-за буферизации. Это происходит при работе с
head
командой из GNU coreutils (найденной в не встроенных системах Linux), когда входные данные поступают из обычного файла. Это потому, что, как только эта реализацияhead
прочитала, что она хочет, она устанавливает позицию файла в первый байт, который она не вывела. Это не работает, если вход представляет собой канал.Более простой способ напечатать несколько последовательностей строк из файла - вызвать более универсальный инструмент, такой как sed или awk . (Это может быть медленнее, но это имеет значение только для очень больших файлов.)
источник
Я знаю, вы сказали, что вам нужно использовать голову и хвост, но sed, безусловно, является более простым инструментом для работы здесь.
Вы даже можете собрать блоки в строку с другим процессом и запустить его через sed.
-n отрицает вывод, затем вы указываете диапазоны для печати с p, где первый и последний номер диапазона разделяются запятой.
При этом вы можете либо выполнить группировку команд, предложенную @don_crissti, либо несколько раз перебрать файл, когда голова / хвост захватывает кусок строки при каждом прохождении.
Чем больше строк в файле и чем больше блоков, тем эффективнее будет работать sed.
источник
С
sed
вами можно сделать:... Возможно, более эффективное решение может быть найдено с
head
. Дон уже продемонстрировал, как это может работать очень хорошо, но я тоже с этим поиграл. Что-то, что вы могли бы сделать, чтобы справиться с этим конкретным случаем:... который будет вызывать
head
4 раза, записывая либо в,outfile
либо в/dev/null
зависимости от того, является ли значение этой итерации$n
четным или нечетным числом.Для более общих случаев я собрал это вместе с некоторыми другими вещами, которые у меня уже были:
Это может сделать вашу вещь, как:
... который печатает ...
Он ожидает, что его первым аргументом будет число повторений с префиксом
-
или, в случае неудачи, просто 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 перестанет существовать, поскольку ее единственная именованная ссылка файловой системы уже удалена.источник
Используйте функцию bash, например:
В этом случае это немного излишне, но если ваши фильтры растут больше, это может стать благом.
источник