ファイル内の文字列を検索したいが末尾の改行で終わらない行の一致を無視します。つまり、ファイルの最後の行が改行で終わらない場合は無視したいと思います。
これを行う最良の方法は何ですか?
subprocess
処理する前に、大きなテキストログファイルをフィルタリングするためにモジュールを介してgrepを呼び出すPythonスクリプトでこの問題が発生しました。ファイルの最後の行が記録されている可能性があり、その場合はその行を処理したくありません。
答え1
使用gawk
(EREのようなものを使用grep -E
):
gawk '/pattern/ && RT' file
RT
in には、gawk
レコード区切り文字に一致するコンテンツが含まれます。RS
デフォルト値RS
(\n
)を使用すると、最後に\n
区切られていないレコードを除いて、レコードRT
は空です。
使用perl
(使用可能なものと同様のPerl RE grep -P
):
perl -ne 'print if /pattern/ && /\n\z/'
gawk
grep
またはとは異なり、perl
デフォルトは文字ではなくバイトに適用されます。たとえば、.
正規表現演算子は、UTF-8でエンコードされた2バイトのそれぞれと一致します£
。ロケールの文字定義(例:awk
/)に従って文字を処理するには、次のようにgrep
します。
perl -Mopen=locale -ne 'print if /pattern/ && /\n\z/'
答え2
grep
明らかに限られた改行文字は無視されるため、実際には使用できません。sed
現在行(断片)が改行で終わるかどうかを内部的に知っていますが、その情報を公開するように強制する方法はわかりません。awk
改行文字(RS
)でレコードを区別しますが、改行文字があるかどうかは実際には関係ありません。デフォルトの動作は、すべての場合、最後に改行文字()を印刷することですprint
。ORS
したがって、一般的なツールはここではあまり役に立たないようです。
しかし、sed
最後の行で作業する時期を知っているので、最後の行の一部を見ずに最後の行全体を失っても構わない場合は、最後の行と思われるものをsed
削除できます。例えば
sed -n -e '$d' -e '/pattern/p' < somefile # or
< somefile sed '$d' | grep ...
それがオプションでない場合は、常にPerlがあります。これにより、/pattern/
末尾に改行文字を含む一致する行のみが印刷されます。
perl -ne 'print if /pattern/ && /\n$/'
答え3
次の操作が実行されます。
#!/usr/bin/env sh
if [ "$(tail -c 1 FILE)" = "" ]
then
printf "Trailing newline found\n"
# grep whole file
# grep ....
else
printf "No trailing newline found\n"
# ignore last line
# head -n -1 FILE | grep ...
fi
以下に説明するコマンド置換機能を使用しますman bash
。
Bash はコマンドを実行し、コマンド置換をコマンドの標準出力に置き換えて拡張を実行します。何でも 末尾の改行を削除します。
答え4
速度が必要な場合は、CでPCRE(または他のより速い正規表現ライブラリ)を使用すると、正規表現を使用して改行を確認できます。欠点:新しいコードを維持してデバッグする必要があり、部分を再実装するのにかかる時間は、式の複雑さやそのような機能を使用するかどうかによって異なりますgrep
。perl
--only-matching
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pcre.h>
#define MAX_OFFSET 3
int main(int argc, char *argv[])
{
// getline
char *line = NULL;
size_t linebuflen = 0;
ssize_t numchars;
// PCRE
const char *error;
int erroffset, rc;
int offsets[MAX_OFFSET];
pcre *re;
if (argc < 2) errx(1, "need regex");
argv++;
if ((re = pcre_compile(*argv, 0, &error, &erroffset, NULL)) == NULL)
err(1, "pcre_compile failed at offset %d: %s", erroffset, error);
while ((numchars = getline(&line, &linebuflen, stdin)) > 0) {
if (line[numchars-1] != '\n') break;
rc = pcre_exec(re, NULL, line, numchars, 0, 0, offsets, MAX_OFFSET);
if (rc > 0) fwrite(line, numchars, 1, stdout);
}
exit(EXIT_SUCCESS);
}
これはperl -ne 'print if /.../ && /\n\z/'
。