For ループと位置指定コマンドの正規表現が一致しません。

For ループと位置指定コマンドの正規表現が一致しません。

構成を変更すると、サフィックスが.originalのソースファイルのコピーが作成されます。これで、すべての* .originalファイルを見つけて、.originalサフィックスがある場合とない場合の両方のバージョンを使用する単純なスクリプトを作成しています。

パスの中央にある文字列とlocateファイルが一致しないことを避けるために、正規表現でコマンドを使用しました。original

私のコマンドはlocate --regex ^.*\\.original$完全に実行されていますin terminal。 .original サフィックスで終わるすべてのファイルを探します。file.original

しかし、in bash scriptで同じコマンドを使用すると、次のバリアントがfor loop返されます。file.original file-original file_original

.originalファイルのみを取得するには、正規表現またはforループをどのように変更する必要がありますか?

私の殻は次のとおりです

$ echo $BASH
/usr/bin/bash

私のbashスクリプトは次のとおりです

#!/usr/bin/bash
echo "Plain locate command:"
locate --regex ^.*\\.original$ | grep test

echo "For loop:"
for file in `locate --regex ^.*\\.original$ | grep test`; do
        echo $file
done 

テストに使用できます。

mkdir /tmp/test 
touch /tmp/test/file.original
touch /tmp/test/file-original
touch /tmp/test/file_original
updatedb
locate --regex ^.*\\.original$

私のターミナルで次を探します。

/tmp/test/file.original

しかし、私のスクリプトでは以下を探します。

Plain locate command:
/tmp/test/file.original
For loop:
/tmp/test/file-original
/tmp/test/file.original
/tmp/test/file_original

答え1

バックティックにはより多くのエスケープが必要です。これがあなたがそれを好むべき理由の1つです$()(この答えの「バックスラッシュの楽しみ」を参照:$(stuff)これらとそしての違いは何ですか`stuff`)。

バックティック内でエスケープ処理が不十分なため、文字列が最終的に正規表現として解釈されたときにエスケープしたい点はエスケープされません。

関連する行を次のように変更します。

for file in $(locate --regex '^.*\.original$' | grep test); do

メモ:

  • バックスラッシュを便利に処理するために単一引用符を使用します。そしてアスタリスク。元のコードでは、引用符がなくエスケープされていないアスタリスクをトリガーできます。ファイル名拡張子

  • ^.*正規表現には何も変更されませんでした。一重引用符で\.original$十分です。^.*ファイル名拡張の可能性を指摘するためにそのまま維持することにしました。

  • に慣れる参照変数(例えばecho "$file")。リンクされた答えも引用を提案しますが、これは$()ループforでは間違っています。引用しないのも$()間違いです。どちらも間違っていたから…

  • 一般的に言えばforこのようなループを作成するのは一般的に間違いです。。これはBashの最初のトラップ。より良い出力でlocate操作を実行するには、xargsnullで終わる文字列として扱うのが最善です。

    locate -0 … | grep -z … | xargs -r0 …
    

    これらのオプションは移植可能ではありません。

関連情報