「find ... -exec」内で「sed」のバックスラッシュをエスケープする方法は?

「find ... -exec」内で「sed」のバックスラッシュをエスケープする方法は?

別のサブディレクトリにある一部のファイルの行を変更したいと思います。ファイルの拡張子は常に存在し、.dct作業ディレクトリの他のサブディレクトリにあるサブディレクトリには常に存在しますmod(ただし、サブディレクトリが多いためmod使用しますfind)。しかし、私が変更したい文字列はディレクトリ(Windows - > Unix)です。

で関連ファイルを入手できますfind . -type f -path '*/mod/*.dct。で関連行を変更してみましたsed -e 's/cd c:\\project\\data\\/cd \/project\/data\//' $(basename {}) > $(basename {}).mod

私は犯人になる脱出されたバックスラッシュで範囲を絞りました。これは働きます:

find . -type -f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/c://' $(basename {}) > $(basename {}).mod"

以下は行われません。

find . -type -f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/c:\\//' $(basename {}) > $(basename {}).mod"

これはエラーです。

sed: -e expression #1, char 7: unterminated `s' command

このchar 7部分は脱出に問題があると思います。そんなようですが、どう修正できるかわかりません。これを説明するために、以下が機能します。

find . -type -f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/c:\\//' $(basename {}) > $(basename {}).mod"

したがって、「何でも置換」sed -e 's/c:\\///'にエスケープされ、「何に置き換え」の代わりに「...に置き換え」(そしてエラーが発生した)にエスケープされたように見えます。c:\/sed -e 's/c:\\//'c:\/c:\

注:代わりに-execdirand を使用するのは少し過剰かもしれませんが、どこかでこれが良い形式であることを読んでいます。basename-exec

答え1

質問の鍵は、fromを呼び出してバックスラッシュ(例\:)をスラッシュ(例:)に置き換える方法です。/これを行うには、文字列が呼び出しによって1回、呼び出しによって2回、2回処理されるため、バックスラッシュを2回エスケープする必要があります。これにより、次の情報が提供されます。sedfindfindsed

find . -type f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/cd c:\\\\project\\\\data\\\\/cd \/project\/data\//' $(basename {}) > $(basename {}).mod" \;

以下は、より詳細な説明です。


まず、問題の少し簡単な例を設定しましょう。

# Create a target directory
mkdir -p /tmp/dir1/mod/dir2

# Create a text file containing a backslash
echo '\' > /tmp/dir1/mod/dir2/file.dct

それではバックスラッシュを使っfindsedそれをスラッシュに変えましょう。

find /tmp/dir1 -type f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/\\/\//' $(basename {})" \;

これにより、次のエラーが発生します。

sed: -e expression #1, char 7: unterminated `s' command

sedこれは、実行されるコマンドが次のようになるためです。

sed -e 's/\/\//' ./file.dct

次のコマンドを直接実行して、同じエラーが発生するかどうかを確認できます。例:

sed -e 's/\/\//' /tmp/dir1/mod/dir2/file.dct

次のコマンドを実行して確認することもできますechofind

find /tmp/dir1 -type f -path '*/mod/*.dct' -execdir echo "sed -e 's/\\/\//' $(basename {})" \;

コマンドを変更するには、バックスラッシュを2回エスケープします。

find . -type f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/\\\\/\//' $(basename {})" \;

これにより、目的の結果が生成されます。

/

関連情報