この質問は私の別の質問から来ました。ここ(「シェルから親ディレクトリのベース名を抽出する方法))、これは「ウサギの穴」を開くようです。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)
a
d
f.zip
a
b
d.zip
$1
$2
$3
$components
その[^/]#
うちのいくつかは、/以外のすべてのシーケンスに一致する#
正規表現演算子と同じです。*
globの場合は、aを拡張できないのと同じように機能します*
が、globを拡張した後、結果ファイルからパターンマッチングを使用して置き換える部分を抽出し、代わりにあまりにも多くの部分に一致するようにaを拡張します。*
/
zmv
*
/
(*)
([^/]#)
答え2
使用は厳しい要件にすぎませんfind
か?exec
むしろ結果を繰り返して、find
次のような文字列操作にやさしいツールと組み合わせたいと思いますawk
。
for ii in $(find . -name "*.zip")
do
mv $ii $(echo $ii|awk -F/ '{print "someString_" $2 "_" $4 "+" $6}')
done
mv
(echo mv
テスト目的で交換しました。)
注:オプションをスペースとタブの代わりに区切り文字に設定してください-F/
。awk
/
修正する
split+glob
Stéphaneのコメントで示唆したように、演算子を調整する方が賢明で強力です。ここ)プレビュー:
IFS=$'\n'
set -f
ファイル名にスペースが含まれている場合は最初の行が必須で、ファイル名にワイルドカードが含まれている場合は2行目は必須です。
今後「奇妙な」行動で自分自身を狂わせたくない場合は、以前の設定に戻すことを忘れないでください...まだこれらの設定をカスタマイズしていないとします。
unset IFS
set +f