パラメータ拡張時の特殊文字エスケープ

パラメータ拡張時の特殊文字エスケープ
file=/tmp/text/foo.txt

/bar次に、パラメータ拡張構文を使用してこのディレクトリ構造にサブフォルダを追加したいと思います。この行の仕組み:

echo "${file%/*}/bar/${file##*/}"

構文で短くすることができるかどうか疑問に思います${parameter/%pat/string}/asを作成しpatてに変更したいです/bar/。しかし、どの部分がファット/部分であるかをシステムにどのように知らせることができるかわかりません。エスケープしようとしましたが\成功しませんでした。私が書いたコードは次のとおりです。

echo "${f/%///bar/}"

または

echo "${f/%\///bar/}"

しかし、それらのどれも動作しません。

ベストアンサー1

使用歴史的修正

for file in /tmp/text/foo.txt /foo.txt foo.txt mydir/; do
  echo $file:h/bar/$file:t
done

システムのルートディレクトリにあるファイルが//some/where異なることに注意してください/some/where。特に、$fileディレクトリ部分がまったくない場合は動作しますが、素朴なバージョンは${file%/*}そうではありません。$fileスラッシュで終わると、空でbarない最後のパスコンポーネントの前に挿入されます。これは望むものでも、そうでないかもしれません。

パラメータ拡張形式を使用すると、次のことができます。${VARIABLE/PATTERN/REPLACEMENT}パラメータ拡張フラグ In番目の一致を選択しますが、残念ながら最後の一致では選択できません。この特定のケースでは動作しますが、echo ${(I:3:)file/\///bar/}ディレクトリレベルが何人かを正確に知る必要があります。以下をカウントできます。

echo ${(I:${#file//[^\/]/}:)file/\///bar/}

ただし、これは複数の部分に分割するよりも複雑で、スラッシュがなければうまく機能しません$file

有効にすると、次のものをextended_glob使用できます。b ワイルドカードフラグパターン内のスラッシュ以外の文字を一致させることができます(ありがとう。# グローバルオペレータ$match)はワイルドカード一致の一部を参照するために使用されます。

setopt extended_glob
for file in /tmp/text/foo.txt /foo.txt foo.txt mydir/; do
  echo ${file/%(#b)([^\/]#)/bar/$match[1]}
done

パターンは、(#b)([^\/]#)スラッシュではなく末尾の文字と一致し、一致する部分をに保存します$match[1]。 zsh ≥5.9を使用すると、オフになっても書き込む${(*)file/%(#b)([^\/]#)/bar/$match[1]}ことができます。extended_globこれは単純ではないが堅牢であるという利点がある。つまり、ディレクトリ部分がないファイル名の一般的な場合と、ルートディレクトリにあるファイルの極端な場合でも結果が正確です。スラッシュで終わるmydir/bar/場合は作成され、必要なものでもそうでない場合もあります。$file

おすすめ記事