web-dev-qa-db-ja.com

パイプを使用せずにファイル内の文字列のgrep

パイプを使用せずに、最後のn行のファイルでWordをgrepしたい。

grep <string> filename

ファイル名で文字列を検索できるようにします。しかし、ファイルの最後のN行で文字列を検索したいと思います。パイプを使用せずにそれを検索するコマンドはありますか?

3
Kai

シェルがそれをサポートしている場合(zshbashkshのいくつかの実装)、 プロセス置換

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]
7
Nicolai S
_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
_
3
mikeserv

なぜパイプを避けたいのですか?

本当にパイプを避けたい場合は、2つのコマンドを実行する必要があります。

tail -N filename > filename.tmp
grep "string" filename.tmp

(when N is the last number of lines)
2
faadi

awkと少しの助けを借りて、それを行うことができます。

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

フォネティックコード の最後の8行にeを含むすべての行を検索します。これには、入力ファイル全体を2回読み取るという欠点があります。

2
Scott