パイプを使用せずにファイル内の文字列を検索する Grep

パイプを使用せずにファイル内の文字列を検索する Grep

パイプを使わずにファイルの最後のn行で単語を見つけるためにgrepを使用したいと思います。

grep <string> filename

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

答え1

シェルがそれをサポートしている場合(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少なくともksh93Linuxでは|いいえパイプを使用しますが、ソケットペアを使用してください。プロセスの交換openパイプを使用してください(ソケットは使用できません)。

$ ksh93 -c '読み取りリンク<(:)'
パイプ: [620224]
$ksh93 -c ': 読み取りリンク /proc/self/fd/0'
ソケット: [621301]

答え2

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

残念ながら、行数を取得するにはファイルを完全に読み取る必要があります。wcそうでなければ、ファイルに何行があるか、どのくらい大きいかは明確ではないからです$n。それ以外に、これは非常にパフォーマンスの良いソリューションでなければなりません<inlseek()有能な文書。

まず、行数を求めて$nその数を減算します。headstdinからその行を読み取り、結果を作成します/dev/null。その後に残ったのは$nstdinの入力行数とユーザーgrepのパターンだけです。

技術的にはこれはトリックです。はいコマンドのパイプはで置き換えられますwc。これを無視しても構いません。

しかし、別のアプローチは次のとおりです。

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

...GNUと一緒にgrep。目標パターンの近くのどこかに現れる別のパターンを持つことができれば、grep $n実際にパイプなしでそれを行うことができます。

私はw /に固執しようとしていますが、grepとにかくsedここに解決策があります。以下のパイプラインは入力専用です。grep行番号の前に追加する以外はまったく関係がないため、どの番号であるかを確認できます。これらはすべて、ケース例にのみ適用されます。sedすべての種類の名前付きファイルまたは標準入力にスクリプトのみを使用でき、$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

なぜパイプを避けるべきですか?

実際にパイプを使用しないようにするには、次の2つのコマンドを実行する必要があります。

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

(when N is the last number of lines)

答え4

awk少し手助けをしたら、これを行うことができます。

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

e最後の8行に含まれるすべての行を検索ピンインのアルファベット。これの欠点は、入力ファイル全体を2回読み取ることです。

関連情報