パイプを使用せずに、最後のn行のファイルでWordをgrepしたい。
grep <string> filename
ファイル名で文字列を検索できるようにします。しかし、ファイルの最後のN行で文字列を検索したいと思います。パイプを使用せずにそれを検索するコマンドはありますか?
シェルがそれをサポートしている場合(zsh
、bash
、ksh
のいくつかの実装)、 プロセス置換
grep <pattern> <(tail -n5 yourfile.txt)
ここで、-n5は、最後の5行を取得することを意味します。
同様に、
grep <pattern> <(head -n5 yourfile.txt)
yourfile.txtの最初の5行を検索します。
説明
簡単に言えば、置換されたプロセスはファイルのふりをします。これはgrepが期待していることです。プロセス置換の利点の1つは、この例のdiff
のように、複数のコマンドからの出力を他のコマンドの入力としてフィードできることです。
diff -y <(brew leaves) <(brew list)
これにより、パイプ(
|
)文字が削除されますが、実際には、各置換はパイプを作成します1。
1少なくともLinuxのksh93
では、|
はではなくパイプを使用しますが、ソケットペアを使用しますプロセス置換はパイプを使用します(ソケットをopen
することはできないため):
$ ksh93 -c'readlink <(:) ' pipe:[620224] $ ksh93 -c':| readlink /proc/self/fd/0' socket:[621301]
_n=$some_num
{ head -n"$(($(wc -l <in)-n))" >/dev/null
grep 'match your string'
} <in
_
残念ながら、これには、行数を取得するためにwc
を介してファイルを完全に読み取る必要があります。そうしないと、ファイル内の行数や_$n
_の大きさが明確にならないためです。それはさておき、_<in
_が通常のlseek()
ableファイルであれば、これは非常にパフォーマンスの高いソリューションになるはずです。
したがって、最初に行数を取得し、そこから_$n
_を減算します。 head
は、stdinからその数の行を読み取り、結果を_/dev/null
_に書き込みます。その後に残るのは、_$n
_- stdinの入力行数と、grep
とパターンだけです。
技術的には、これはチートを行います-そこにiswc
のコマンド置換のパイプ。それを見逃していただければ幸いです。
ちなみに、これを行う別の方法は次のようになります。
_{ grep "-m$n" 'some pattern near yours' >/dev/null
grep 'your pattern'
} <in
_
... GNU grep
。可能であればgrep
_$n
_別のパターンが発生し、ターゲットの近くに移動しますパターン、それならあなたは本当にパイプなしでそれをするかもしれません。
grep
で固執しようとしましたが、とにかくここにsed
ソリューションがあります。以下のパイプは入力用です-そしてgrep
は行番号を付加するためにまったく関与していないので、それらがどの番号であるかを確認できます。それはすべて、例の場合のみです。 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
_
なぜパイプを避けたいのですか?
本当にパイプを避けたい場合は、2つのコマンドを実行する必要があります。
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
$
フォネティックコード の最後の8行にe
を含むすべての行を検索します。これには、入力ファイル全体を2回読み取るという欠点があります。