たとえば、という名前のホームディレクトリがありますmain
。このホームディレクトリにはいくつかのフォルダがあり、その中にはというccc
ddd
名前の3つのフォルダがありますがlll
、これらのフォルダだけを見つけて処理したいと思います。各サブフォルダには、3 つのサブフォルダすべてに同じ名前のフォルダがあるため、サブフォルダにはccc
ddd
lll
同じ名前のフォルダが含まれます。
次に、その中の各サブフォルダには、thisなどのccc
ddd
lll
特定の名前を持つ複数のファイルがあります。c_000
d_000
l_000
c_001
d_001
l_001
私が最初にしたことは、次のようにファイル名の先頭に2つの親ディレクトリが追加されるようにファイル名を変更することでしたccc_foo1_c_000
ddd_foo1_d_000
lll_foo1_l_000
。スクリプトでこれを行う方法を提案できる人がいるかどうか尋ねました.sh
。
私のホームフォルダの簡単なツリー構造は次のとおりです。
.
`-- main
|-- ccc
| `-- foO1
| | |-- c_000
| | `-- c_001
| |
-- foo2
| |-- c_000
| `-- c_001
|
|
|-- ddd
| `-- foO1
| | |-- d_000
| | `-- d_001
| |
-- foo2
| |-- d_000
| `-- d_001
|-- lll
| `-- foO1
| | |-- l_000
| | `-- l_001
| |
| -- foo2
| |-- l_000
| `-- l_001
|
|-- aaa
|-- bbb
答え1
次のことができます。
for dir in ccc ddd lll; do
find "main/$dir" -type f -print0 |
while IFS= read -r -d '' f; do
dd=$(dirname "$f")
new="${f/main\/}"
new="${new//\//_}"
mv "$f" "$dd"/"$new"
done
done
上記のスクリプトを完了すると、ファイルは次のようになります。
.
`-- main
|-- ccc
| |-- fo01
| | |-- ccc_fo01_c_000
| | `-- ccc_fo01_c_001
| `-- fo02
| |-- ccc_fo02_c_000
| `-- ccc_fo02_c_001
|-- ddd
| |-- fo01
| | |-- ddd_fo01_d_000
| | `-- ddd_fo01_d_001
| `-- fo02
| |-- ddd_fo02_d_000
| `-- ddd_fo02_d_001
`-- lll
|-- fo01
| |-- lll_fo01_l_000
| `-- lll_fo01_l_001
`-- fo02
|-- lll_fo02_l_000
`-- lll_fo02_l_001
説明する
for dir in ccc ddd lll; do ...; done
:これらの3つのディレクトリ名に対してのみこれを行い、個別に$dir
。find "main/$dir" -type f -print0 |
type f
:()内のすべてのファイルを見つけて、空の文字列()で区切って印刷して、ファイル/ディレクトリ名に改行文字が含まれていても正しく機能することを確認しますmain/$dir
。-print0
while IFS= read -r -d '' f; do
:これは結果を繰り返してfind
各結果をとして保存します$f
。バックスラッシュが特に処理されず、nullで区切られた入力を読み取ることができるようにIFS=
スペースを破ることは避けてください。-r
-d ''
dd=$(dirname "$f")
:$dd
Now は現在ファイルがあるディレクトリです。たとえば、main/ccc/fo01
。new="${f/main\/}"
:シェルを使用しています。文字列演算main/
ファイルパスから文字列を削除する機能。new="${new//\//_}"
:上記のように、すべてを下線に置き換えます/
。これにより、同様の文字列が生成されますccc_fo01_c000
。mv "$f" "$dd"/"$new"
:最後に、元のファイルの$f
名前を$dd/$new
。$dd
$new
実際にこれを行う前にテストするecho
前に追加することをお勧めしますmv
。
答え2
これは、ファイルを繰り返して名前のディレクトリ部分を解析して1つずつ名前を変更する単純なPOSIXシェルソリューションです。
for x in ccc/*/* ddd/*/* lll/*/*; do
dir2=${x%/*}; dir1=${dir2%/*}; dir2=${dir2#"$dir1"}
mv -- "$x" "${x%/*}/${dir1}_${dir2}_${x##*/}"
done
Bashでは、次のものを使用できます。パラメータ拡張ファイル名の解析を防ぐための文字列置換機能です。
for x in ccc/*/* ddd/*/* lll/*/*; do
mv -- "$x" "${x%/*}/${x//\//_}"
done
zshでは利用可能ですzmv
パターンに従ってファイル名を変更します。
autoload -U zmv
zmv '(ccc|ddd|lll)/(*)/(*)' '$1/$2/${1}_${2}_$3'
答え3
ソフトコーディングされたソリューションの場合は、ディレクトリで実行されますmain
。
#!/bin/bash
for f in $(find . -name '*_00*'); do
mv "$f" "$(dirname "$f")/$(dirname "${f:2}" | tr "/" "_")_$(basename $f)"
done
これは、すべてのディレクトリを再帰的に参照して、パターンを含むすべてのファイルを見つける必要があります*_00*
。各ファイルは、パス($(dirname $"f")
)、アンダースコア、および削除された最初の2文字を含む変換パス()、および$(dirname "${f:2}" | tr "/" "_")
元のファイル名自体()の$(basename $f)
組み合わせを使用して個別に名前が変更されます。