grep "^$1"のような動作ですが、エスケープするにはどうすればよいですか"$1"なので、grepはその中の文字を特別に解釈しませんか?

またはより良い方法はありますか?

編集: "^$1"を検索したくないが、動的に挿入された固定文字列のみを検索する行の先頭にある場合は一致します。これが、$1の意味です。

コメント

  • 二重引用符の代わりに一重引用符を使用しようとしましたか? grep '^$1'?または、' $1がシェルによって展開されないようにしたいという意味ではありませんか?
  • @mnille ' ' ^ $ 1 'を検索したくないが、動的に挿入されたものを検索したい行頭に'ある場合にのみ一致する必要がある固定文字列。これは、'が$ 1の意味です。
  • grepでも実行できますが、'最初に文字列内の特殊文字をエスケープする必要があります。 printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti 'は他の回答よりも優れています。気になりますか?
  • @ roaima-わかっていますが、'にはすでにたくさんの回答があり、これ(変数内の特殊文字をエスケープ)は私(およびここにいる他の数人のユーザー)はかなり長い間家に帰ってきました…必要に応じていつでも回答に追加できます。'削除しますここにコメントします('不足している先頭の中括弧を追加することを忘れないでください)。

回答

grepを使用してこれを行う方法を考えることはできません; ^自体はの一部です正規表現を使用するには、正規表現を解釈する必要があります。awkperlなどで部分文字列の一致を使用するのは簡単です:

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)は長さがゼロの文字列ではありません。それ以外の場合、cutvalues 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" 

この質問を参照してください。必要に応じて、詳細については PCRE doc を参照してください。

回答

フィルターとして:

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"(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 

を使用します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です