Intereting Posts
копирование и работа с файлами (папками) OSX .app в linux dd для резервного копирования и восстановления полной системы Как получить CoreAudio от Mac до Linux / Unix? Как остановить дисковое приложение gnome от спам-сообщений с сообщениями об ошибках диска до тех пор, пока моя X-сессия не замерзнет? Сценарий для удаления текстовых файлов Обновление остановлено, и система больше не запускается Корень не может изменять разрешение или право собственности на файл Поддерживает ли netcat аутентификацию прокси-сервера? Начать несколько рыбных снарядов в разных каталогах? Мой сетевой адаптер Atheros Ethernet не работает с клиентом Xen Redhat Где / usr / lib64 go и что такое / usr / lib / x86_64-linux-gnu? Сценарий оболочки для поиска и замены значения из файла csv lxc и sched_setscheduler Почему debian unstable предпочитает устанавливать cgmanager? Является ли установка базовых файлов: i386 безопасен?

Grep для строки в файле без использования трубы

Я хочу grep для слова в файле в последних n строках без использования канала.

grep <string> filename 

позволяет искать имя файла для строки. Но я хочу найти строку в последних N строках файла. Любая команда для поиска этого без использования трубы?

Если ваша оболочка поддерживает его ( zsh , bash , некоторые реализации ksh ), вы можете использовать замещение процесса

 grep <pattern> <(tail -n5 yourfile.txt) 

Где -n5 означает получить пять последних строк.

По аналогии,

 grep <pattern> <(head -n5 yourfile.txt) 

будет искать через 5 первых строк файла yourfile.txt.

объяснение

Проще говоря, замещенный процесс притворяется файлом, который ожидает Grep. Одним из преимуществ замены процесса является то, что вы можете подавать выходные данные из нескольких команд в качестве ввода для других команд, например diff в этом примере.

 diff -y <(brew leaves) <(brew list) 

Это избавляет от символа трубы ( | ), но каждая замена фактически создает трубу 1 .


1 Обратите внимание, что с ksh93 по Linux, по крайней мере, | не использует трубку, а пару сокетов, в то время как подстановка процесса использует канал (так как невозможно open сокет):

 $ ksh93 -c 'readlink <(:)'
 Труба: [620224]
 $ ksh93 -c ': |  readlink / proc / self / fd / 0 '
 Гнездо: [621301]

 n=$some_num { head -n"$(($(wc -l <in)-n))" >/dev/null grep 'match your string' } <in 

К сожалению, для этого требуется прочитать файл целиком через w / wc чтобы получить подсчет строк, потому что неясно, сколько строк в файле или сколько больших $n . В остальном это должно быть очень эффективным решением, если <in является регулярным, lseek() способным файлом.

Итак, сначала мы получаем количество строк и вычитаем из него $n . head читает в том, что многие строки из stdin и записывают результаты в /dev/null . Остается после этого $n -count строк ввода на stdin и только ваш grep и ваш шаблон.

Технически это чит – в подстановке команд для wc есть труба. Я надеюсь, что вы можете это упустить.

Кстати, другой способ сделать это может выглядеть так:

 { grep "-m$n" 'some pattern near yours' >/dev/null grep 'your pattern' } <in 

… с GNU grep . Если вы можете grep $n вхождения другого шаблона, который доставит вас по соседству с вашим целевым шаблоном, вы можете действительно сделать это без трубы вообще.

Я пытался вставить w / grep , но в любом случае это решение sed . Нижеследующие трубы предназначены только для ввода – и grep не участвует во всех expet для добавления номеров строк, чтобы вы могли видеть, какие номера они есть. Все это только для примера. Вы можете использовать сценарий sed только с именованным файлом или stdin любого типа и установить $pat и $n соответственно, и он будет работать.

Я на самом деле просто переписал это, потому что мне не понравилось, что я не смог привязать матчи. Это немного медленнее – не заметно, и это все еще очень быстро, но для каждой буферизованной хвостовой линии он обрезает все конечное пространство шаблонов и изолирует первую строку в буфере. Таким образом, все нормальные якорные выражения работают так, как ожидалось.

 pat=man n=40 man man | grep -n ''| sed -e:B -e'${/^\n/D' \ -eh -e's/\n.*//' \ -e"/$pat/p;x" \ -e\} -e'$D;N;$bB' \ -e"$n,$ D;bB" 

 648: /etc/man_db.conf 649: man-db configuration file. 651: /usr/share/man 652: A global manual page hierarchy. 654: /usr/share/man/index.(bt|db|dir|pag) 657: /var/cache/man/index.(bt|db|dir|pag) 661: apropos(1), groff(1), less(1), manpath(1), nroff(1), troff(1), whatis(1), 662: zsoelim(1), setlocale(3), manpath(5), ascii(7), latin1(7), man(7), cat- 663: man(8), mandb(8), the man-db package manual, FSSTND 680: developing and maintaining man-db. 

Вот еще один пример, но в файле:

 pat=. n=15 seq 100 >nums sed -e:B -e'${/^\n/D' \ -eh -e's/\n.*//' \ -e"/$pat/p;x" \ -e\} -e'$D;N;$bB' \ <nums -e"$n,$ D;bB" 

 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 

Почему вы хотите избежать трубы?

Если вы действительно хотите избежать трубы, вам придется запустить две команды:

 tail -N filename > filename.tmp grep "string" filename.tmp (when N is the last number of lines) 

Вы можете сделать это с помощью awk и немного помочь:

 $ N=8 $ awk -v start_line="$(( $(wc -l < alphabet) - N + 1 ))" 'NR>=start_line && /e/' alphabet sierra whiskey yankee $ 

находит все строки, содержащие e в последних 8 строках фонетического алфавита . Это имеет недостаток, что он дважды считывает весь входной файл.