Bashは変数内の引用符を引用符ではなくテキストとして読み込みますか? Bashに「暗黙の参照」がありますか?

Bashは変数内の引用符を引用符ではなくテキストとして読み込みますか? Bashに「暗黙の参照」がありますか?

メールキューを定期的にクリーンアップするbashスクリプトがあります。何らかの理由で、私たちは@mms.att.netやその他のemail2SMSゲートウェイに送信され、9時間以上待ち行列にあったがまだ配信されていないすべての電子メールを削除することにしました。

簡単に言えば、このスクリプトは次のことを行います。

domains=`cat /etc/mail/email2textdomains.txt`
egrep $domains /var/log/maillog | .... other tasks

内容は/etc/mail/email2textdomains.txt正しい

"mms.att.net|vtxt.com|vtext.com|vzwpix.com"

したがって、egrep 行は次のようになります。これは私がコマンドラインに入力したのとまったく同じです。

egrep "mms.att.net|vtxt.com|vtext.com|vzwpix.com" file | ...

これを実行すると、5つ以上のステップコマンドパイプラインになり、各コマンドは古いstdoutからstdinを読み込みます。これは明らかに私が望む検索ではありません。

egrep  mms.att.net|vtxt.com|vtext.com|vzwpix.com  file | ...

ただし、実行時に2つの二重引用符は異なる方法で処理されます。つまり、文字列の一部になるので、本質的に次を検索します。

  • 「mms.att.net
  • vtxt.com
  • vtext.com
  • vzwpix.com」

明らかに私は引用がどのように機能するか誤解しました。解決策は、含まれている行を変更して二重引用符を削除することでした。

パイプでテストしようとしましたが、od -a印刷されていない文字は表示されません。

コンテンツが/etc/mail/email2textdomains.txt正しく機能するように機能する理由

mms.att.net|vtxt.com|vtext.com|vzwpix.com

作成したとおり、長い間失敗するパイプラインはいつ必要ですか?

ベストアンサー1

この種のタスクをデバッグするのに役立つツールはですset -x。これにより、コマンドが実行する操作を正確に確認できます。

$ set -x
$ domains=$(cat domains.txt)
++ cat domains.txt
+ domains='"mms.att.net|vtxt.com|vtext.com|vzwpix.com"'

ご覧のとおり、引用$domains符が含まれています。したがって、次のように使用するとgrep

$ grep -E -- "$domains" file
+ grep --color -E -- '"mms.att.net|vtxt.com|vtext.com|vzwpix.com"' file

あなたが望むのは、シェルレベルで引用符を使用することです。今後データはgrepコマンドに渡されますが、引用符は変数データの一部であるため、他の文字のように扱われます。最も簡単な解決策は、ファイルから引用符を削除し、変数のみを引用することです。これはとにかくベストプラクティスです。

domains=$(tr -d \" < domains.txt) &&
grep -E -- "$domains" file

ところで、usingは前者がより明確でより多くのネストを可能にし、もはや使用されないのでvar=$(command)usingよりも優先されます。var=`command`egrepgrep -E

また、これは単一文字に一致する正規表現演算子であるため、実際には単一文字の後に単一文字の後に続く行を.探します。grep mms.att.netたとえば、を含むものとも一致します。mmsattnethammstattinet.com

したがって、Eこれらのドメインを含む行に一致する拡張正規表現を作成するには、sを削除するだけでなく、"ドメイン名から正規表現演算子であるすべての文字をエスケープする必要があります。有効なドメイン名の場合.

また、実装によっては空の正規表現に対して異なる動作がありgrepますが、ほとんどはすべての行を報告するため、特に処理する必要があります。

だから:

regex=$(
  sed 's/"//g; # remove all "s like with tr
       s/\./\\./g; # substitute .s with \.s
      ' domains.txt
) && 
  [ -n "$regex" ] && # check it's not empty 
  grep -E -- "$regex" file

あるいは、|s を改行文字に置き換え、(以前)-Fオプションを使用して固定文字列を検索することもできます。grepfgrepF

domains=$(<domains.txt tr -d '"' | tr '|' '\n') &&
  [ -n "$domains" ] &&
  grep -F -- "$domains" file

おすすめ記事