「find」と一緒に使用したときに「dirname」の一部を正しく抽出する方法は?

「find」と一緒に使用したときに「dirname」の一部を正しく抽出する方法は?

この質問は私の別の質問から来ました。ここ(「シェルから親ディレクトリのベース名を抽出する方法))、これは「ウサギの穴」を開くようです。Unix文字列操作私のため。それでは、次は補足の質問です。

dirname結果からさまざまな部分(「レベル」)を抽出する正しい方法は何ですかfind

次のような階層があるとしましょう。

DE_AT/adventure/motovun/300x250/A2_300x250.zip

次のようにファイルを「検索」します。

find . -name "*.zip" 

シェル結果の実行find:

-exec sh -c '' {} \;

フルパスの各部分をどのように抽出しますか?入手方法:

  • DE_AT
  • 冒険
  • モトブン
  • 300×250
  • A2_300x250.zip

私が今まで知っているのは次のとおりです。

basename "$1" # gets me: A2_300x250.zip
dirname "$1"  # gets me: ./DE_AT/adventure/motovun/300x250

この.zipファイルの名前を次のように変更する必要があるため、これを尋ねることです。someString_DE_AT_motovun+A2_300x250.zip

私は次のような恐ろしいFrankenソリューションを思いついた。

find . -name "*.zip" -exec sh -c '
    mv "$0" "myString_$(basename $(dirname $(dirname \
    $(dirname "$0")_...+$(basename "$0")"
' {} \;

これが正しい方法がないので、私はこれを試したくありません。

ベストアンサー1

演算子を使用できますsplit+glob

find . -name '*.zip' -exec sh -c '
   IFS=/ # split on /
   set -f # disable glob
   for file do
     set -- $file # invoke split+glob, store in positional parameters
     # now the path components are in $1, $2...
     mv -i -- "$file" "someString_${2}_${4}+${6}"
   done' sh {} +

$1あるでしょう.$2 DE_ATちょっと待ってください。最後のパラメータを取得するには、次のようなものが必要なため、難しくなります。

eval "last=\${$#}"

zshたとえば、適切な分割演算子と配列を使用して他のシェルを使用する方が簡単です。

find . -name '*.zip' -exec zsh -c '
   for file do
     components=(${(s:/:)file})
     printf "Last component: %s\n" $components[-1]
     mv -i -- "$file" "someString_$components[2]_$components[-3]+$components[-1]"
   done' zsh {} +

これにより、zsh以下を使用することもできます。zmvバッチの名前変更ツール:

autoload zmv # best in ~/.zshrc
zmv -n '([^/]#)/**/(*)/*/(*.zip)' 'someString_${1}_${2}+$3'

このセクションはすべてのレベル(レベル0を含む)のサブディレクトリと一致するため、置換のために**///に入るキャプチャ文字列(//、//)と一致して、上記の配列メソッドと同様の動作を提供します。(a)/b/c/(d)/e/(f.zip)(a)/(b)/c/(d.zip)adf.zipabd.zip$1$2$3$components

その[^/]#うちのいくつかは、/以外のすべてのシーケンスに一致する#正規表現演算子と同じです。*globの場合は、aを拡張できないのと同じように機能します*が、globを拡張した後、結果ファイルからパターンマッチングを使用して置き換える部分を抽出し、代わりにあまりにも多くの部分に一致するようにaを拡張します。*/zmv*/(*)([^/]#)

おすすめ記事