grep "^$1"
のような動作ですが、どうすればエスケープできますか"$1"
なので、grepはその中の文字を特別に解釈しませんか?
またはより良い方法はありますか?
編集: "^$1"
を検索したくないが、動的に挿入された固定文字列のみを検索する行の先頭にある場合は一致します。これが、$1
の意味です。
コメント
回答
grep
を使用してこれを行う方法を考えることはできません; ^
自体は正規表現を使用するには、正規表現を解釈する必要があります。awk
、perl
などで部分文字列の一致を使用するのは簡単です:
awk -v search="$1" "substr($0, 1, length(search)) == search { print }"
\
を含む検索文字列を処理するには、 123の答え:
search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }"
コメント
- これは'このような文字列では機能しません
\/
- @ 123として、確かに、私は'それを処理するためのバリアントを追加しました。
- プログラムで
\\///\\/
として表示される\\\/\/\/\\\\/
などの複雑な文字列では引き続き失敗します。私の知る限り、awkでバックスラッシュを適切にエスケープする方法は、事前に使用される数がわからない限りありません。 - @ 123ありがとう、I 'エスケープ処理を回避するために環境を通過するというトリックを適応させました。
- 私はまだこのソリューションが一番好きです。効率的(awk +見回す時間を無駄にしない)、クイックスタートアップ(awk +状態をセットアップするための追加プロセスは不要)は標準ツールを使用し、非常に簡潔です。他のすべての答えは、これらの少なくともいくつかを欠いています。 (grepは比類のない速度で知られているため、効率はここでの強みです。)
回答
一致するものが見つかったかどうかを確認し、すべての入力行を目的のプレフィックス($1
)の長さにカットしてから、固定パターンのgrepを使用する必要があります。
if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi
一致する行の数を取得するのも簡単です:
cut -c 1-"${#1}" | grep -cF "$1"
またはの行番号一致するすべての行(行番号は1から始まります):
cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1
行番号をhead
にフィードしてtail
一致する行の全文を取得しますが、その時点では、PythonやRubyなどの最新のスクリプト言語にアクセスする方が簡単です。
(上記の例では、Posixのgrepとcutを想定しています。検索するファイルは標準入力からのものであると想定していますが、代わりにファイル名を取得するように簡単に調整できます。)
編集:パターン( $1
)は長さがゼロの文字列ではありません。それ以外の場合、cut
はvalues may not include zero
と言って失敗します。また、Bashを使用している場合は、set -o pipefail
を使用してエラーをキャッチします-cut
で終了します。
回答
バックスラッシュを尊重するperlを使用する方法
v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file
これにより、環境変数vが設定されます。コマンドを実行し、変数のインデックスが0、つまり行の先頭の場合に出力します。
awkでも同じことができます
v="$1" awk "index($0, ENVIRON["v"])==1" file
回答
これはすべてbashオプションです。テキスト処理にbashをお勧めしますが、機能します。
#!/usr/bin/env bash # searches for $1 at the beginning of the line of its input len=${#1} while IFS= read -r line do [[ "${line:0:len}" = "$1" ]] && printf "%s\n" "$line" done
スクリプトは長さを計算します入力されたパラメーター$ 1のlen
は、各行のパラメーター展開を使用して、最初のlen
文字が$ 1と一致するかどうかを確認します。一致する場合は、行を出力します。
回答
$1
が純粋なASCIIであり、 grep
には-P
オプション(PCREを有効にするため)があり、これを行うことができます:
#!/bin/bash line_start="$1" line_start_raw=$(printf "%s" "$line_start" | od -v -t x1 -An) line_start_hex=$(printf "\\x%s" $line_start_raw) grep -P "^$line_start_hex"
ここでの考え方は、grep -P
がは、リテラル文字を指定します。ここで、XX
は、その文字の16進ASCII値です。文字erは、それ以外の場合は特殊な正規表現文字であっても、文字通り一致します。
od
は、予想される行の先頭を16進値のリストに変換するために使用されます。次に、printfによってそれぞれの前に\x
が付けられてつなぎ合わされます。次に、^
の前にこの文字列を追加して、必要な正規表現を作成します。
$1
がユニコードの場合、 od
によって出力される文字と16進バイトの1:1の対応がないため、これはかなり難しくなります。
回答
grepに-Pオプションがある場合、これは PCRE 、これを行うことができます:
grep -P "^\Q$1\E"
回答
フィルターとして:
perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern
1つ以上のファイルで実行:
perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file..
perlreドキュメントの「メタ文字の引用」セクションの説明:
引用メタ文字
Pのバックスラッシュされたメタ文字erlは、
\b
、\w
、\n
などの英数字です。他の正規表現言語とは異なり、英数字以外のバックスラッシュ記号はありません。つまり、\\
、\(
、\)
、、\]
、\{
、または\}
は常に次のように解釈されますメタ文字ではなく、文字通りの文字。これはかつて、パターンに使用する文字列内の正規表現メタ文字の特別な意味を無効化または引用するために、一般的なイディオムで使用されていました。 「単語」以外のすべての文字を引用するだけです:$pattern =~ s/(\W)/\\$1/g;
(
use locale
が設定されている場合、これは現在のロケール。)今日では、quotemeta
関数または\Q
メタ引用エスケープシーケンスを使用して、すべてのメタ文字の特別な意味を無効にするのが一般的です。このように:/$unquoted\Q$quoted\E$unquoted/
\Q
と\Q
の間に文字通りの円記号(引用符で囲まれていないもの)を入れる場合は注意してください\E
、二重引用符のバックスラッシュ補間は、混乱を招く結果につながる可能性があります。\Q...\E
内でリテラルの円記号を使用する必要がある場合は、perlop の「引用符で囲まれた構造の解析の詳細」を参照してください。
quotemeta
と\Q
については、 quotemeta で詳しく説明しています。 a>。
回答
自分が持っていない文字がある場合「使用しないでください。これを使用して、行の先頭をマークできます。たとえば、$"\a"
(ASCII 007)。醜いですが、機能します:
{ echo "this is a line to match"; echo "but this is not"; } >file.txt stuffing=$"\a" # Guaranteed never to appear in your source text required="this" # What we want to match that beginning of a line match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//") if [[ -n "$match" ]] then echo "Yay. We have a match: $match" fi
一致する行が必要ない場合は、末尾のsed
を削除してgrep -qF
。ただし、awk
(またはperl
)を使用するとはるかに簡単になります…
回答
ループのないファイルを検索する場合は、次を使用できます。
検索の長さでファイルを切り取ります文字列
固定文字列を探して行番号を返す
grep -Fn "$1" <(cut -c1-${#1} < file)
sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file
これらの行を削除する場合は、
sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file
を使用します。
grep '^$1'
?または、'$1
がシェルによって展開されないようにしたいという意味ですか?grep
でも実行できますが、'最初に文字列内の特殊文字をエスケープする必要があります。例:printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile