web-dev-qa-db-ja.com

pax、無効な置換文字列オプション

paxを使用するPerlスクリプトで何が起こっているのか理解するのに少し問題があります。

背景:.tgzファイルをpaxにフィードし、解凍してフォルダーをファイルでいっぱいにします。

これは私が理解していないことです:

pax -r -z -s '/.*\\//directory\\//p' -f $input_path/$tgz

ここで、$input_pathはパスを含むPerlのスカラー変数であり、$tgz.tgzファイルの名前を含む別のスカラー変数です。

したがって、読み取り用の-rは理にかなっていますが、解凍用の-zは問題ありません。 -sフラグと-fフラグは私を混乱させます。次のエラーが発生します:pax: Invalid replacement string option /.*\\//directory\\//p

フラグの仕組み:

-f、これは問題ではないようです。これは、ファイルを配置する場所です。

-s.tgzファイルに含まれるファイルの名前を変更するための文字列置換。

/.*\\//directory\\//pの部分をわかりやすく説明することはできますか。ここで何が起こっているのか、すべてのエスケープスラッシュで実際に理解できるわけではないので、\pは何かをしなければなりませんが、何がわかりません。 ?

1
Christopher

Paxは/.*\\//directory\\//pを次のように解析します。

  • /は区切り文字です。
  • .*\\は正規表現であり、バックスラッシュで終わる任意の文字列に一致します(バックスラッシュは次の文字を引用します)。
  • /は、正規表現を置換テキストから分離します。
  • /は置換テキストを終了します。
  • directory\\//pはゴミを追跡しています。

明らかに、スラッシュを保護するためにバックスラッシュを使用して、スラッシュがセパレータではなく正規表現の一部になるようにするつもりでした。シェルスクリプトの場合、そこに余分な円記号があります(ただし、これはPerlスクリプトで発生しているためである可能性があります。これについては、後で詳しく説明します)。スラッシュにも問題があります。パスからany/leading/prefix/up/to/directoryを削除する場合は、

pax -r -z -s '/.*\/directory\///p' -f "$input_path/$tgz"

別のセパレータを使用すると読みやすくなります。そうすれば、スラッシュをエスケープする必要はありません。

pax -r -z -s '!.*/directory/!!p' -f "$input_path/$tgz"

これはすべて、コマンドがシェルコマンドであることを前提としています。あなたはPerlスクリプトについて言及しています。 Perlは独自の引用レイヤーを追加するため、何を書き込むかは、文字列がPerlスクリプトにどのように挿入されるかによって異なります。 $input_path/$tgzの使用は、文字列をシェルスクリプトに補間するため、間違いなく問題があります。そのため、文字列はファイル名ではなくシェルスニペットとして解析されます。

Shellコマンドが二重引用符またはバックティックの間にある場合、バックスラッシュは2倍にする必要があります。置き忘れのスラッシュの問題はまだあります。これをPerlで書く方法は次のとおりです。

my $quoted_file_name = quotemeta("$input_path/$tgz");
system("pax -r -z -s '!.*/directory/!!p' -f $quoted_file_name");

systemを使用している場合は、代わりにリストフォームを使用して、中間シェルを呼び出さないことで引用の問題を回避する必要があります。

system('pax', '-r', '-z', '-s', '!.*/directory/!!p', '-f', "$input_path/$tgz");