web-dev-qa-db-ja.com

重複するファイル名を持つ複雑なフォルダー構造のフラット化

複雑なフォルダ構造のフォルダがあります。

├── folder1
│   ├── 0001.jpg
│   └── 0002.jpg
├── folder2
│   ├── 0001.jpg
│   └── 0002.jpg
├── folder3
│    └── folder4
│         ├── 0001.jpg
│         └── 0002.jpg
└── folder5
     └── folder6
           └── folder7
                ├── 0001.jpg
                └── 0002.jpg   

すべてのファイルがfolder1_0001.jpg、folder1_0002.jpg ... folder5_folder6_folder7_0001.jpgなどの一意の名前で親ディレクトリに存在するようにフォルダー構造をフラット化したいと思います。

"Flattening folder structure" で提案されているコードを使用しようとしました

$ find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

echoは、それが機能していることを示しています。

mv folder3/folder4/000098.jpg folder3_folder4_000098.jpg

ただし、出力ファイルは親ディレクトリに配置されません。ドライブ全体を検索しましたが、出力ファイルが見つかりません。

私も試みました "フォルダ構造をBashのファイル名にフラット化する"

$ find . -type f -name "*.jpg" | sed 'h;y/\//_/;H;g;s/\n/ /g;s/^/cp -v /' | sh

-vは、それが機能していることを示しています。

‘./folder3/folder4/000098.jpg’ -> ‘._folder3_folder4_000098.jpg’

ただし、出力によって親ディレクトリに隠しファイルが作成されるため、ワークフローが複雑になります。 ls -aを使用して、親ディレクトリにあるこれらの隠しファイルを表示できます。

また、以下の推奨コードを試してみました "Flatten Foldersコマンドを使用して重複ファイルの名前を変更する"

find . -mindepth 2 -type f | xargs mv --backup=numbered -t . && find . -type d -empty -delete

ただし、このコマンドは、類似したファイル名のファイルを上書きします。

同様の名前のファイルを上書きせずに複雑なフォルダー構造をフラット化する方法についての提案はありますか?現在のソリューションは、1層の深さのフォルダー構造でのみ機能するようです。

私の最終的な目標は、 "フォルダ内のファイルの名前を連番に変更する" で説明されているように、一意の名前を連番に変換することです。

 a=1
  for i in *.jpg; do
  new=$(printf "%04d.jpg" "$a") #04 pad to length of 4
  mv -- "$i" "$new"
  let a=a+1
 done
2
Andrew Brown

あなたの質問の最初の解決策がうまくいかない理由がわかりません。 echoを削除するのを忘れたと思います。とはいえ、bashを実行していると仮定して、必要なことを実行する必要がある別のアプローチを次に示します。

shopt -s globstar
for i in **/*jpg; do mv "$i" "${i//\//_}"; done

説明

  • shopt -s globstarは、bashのglobstar機能をオンにして、**を任意の数のディレクトリまたはファイルに再帰的に一致させます。
  • for i in **/*jpg;は、名前が.jpgで終わるすべてのファイル(またはディレクトリ)を反復処理し、それぞれを$iとして保存します。
  • "${i//\//_}"は、現在のファイル(またはディレクトリ)の名前であり、/のすべてのインスタンスが_に置き換えられています。

名前が.jpgで終わるディレクトリもあり、それらをスキップしたい場合は、代わりに次のようにします。

shopt -s globstar
for i in **/*jpg; do [ -f "$i" ] && echo mv "$i" "${i//\//_}"; done

そして、拡張子に関係なく、すべてのファイルについて:

shopt -s globstar
for i in **/*; do [ -f "$i" ] && echo mv "$i" "${i//\//_}"; done
6
terdon

Perl renameprenameと呼ばれることもあります)がある場合は、次のように実行できます。

find folder* -type f -name '*.jpg' -exec rename 's!/!_!g' {} \;

これにより、各ファイル名パスが取得され、出現するすべての/_に置き換えられます。

実際にファイルの名前を一連の連続する4桁のファイル名に変更する場合は、元のデータセットでこれを使用できる場合があります。これは、ディレクトリ名とファイル名に通常の英数字が含まれている場合にのみ機能します(具体的には、スペース、シェルの句読点、またはその他の空白が存在する場合は失敗します)。

rename 's!.*!sprintf "%04d.jpg", ++$a!e' $(find folder* -type f -name '*.jpg' | sort)

rename -n ...を使用して、何かを変更するとどうなるかを確認するか、rename -v ...を使用して、実行中に発生することを確認します。

2
roaima
pax -rws'|/|_|g' folder*/ .

...ファイル名をオーバーラップする方法がない限り機能します。これをより安全に行うには、-lリンクオプションを使用し、ツリーを別のパスにミラーリングしてから、古いツリーを削除する前に新しいツリーを検査します。

1
mikeserv