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}
パラメータ拡張フラグ I
n番目の一致を選択しますが、残念ながら最後の一致では選択できません。この特定のケースでは動作しますが、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