フォルダ名をファイル名の前に付けてファイルを 1 つ上のレベルに移動しますか?

フォルダ名をファイル名の前に付けてファイルを 1 つ上のレベルに移動しますか?

テスト環境:

  • 0からまでのディレクトリを作成し、 からまでの9ファイルで埋めます。az
    $ mkdir {0..9} && touch {0..9}/{a..z}
    
  • の結果find
    $ find -type f
    ./0/a
    ./0/b
    
    ...
    
    ./9/y
    ./9/z
    

出力を次のように変換するにはどうすればよいでしょうか。

./0a    
./0b

...

./9y
./9z

答え1

Perl のスタンドアロンrenameコマンドを使用する場合:

rename -n 's|/||' */*

すべて問題がなければ、削除して-nから残りの空のディレクトリを削除します。

rmdir {0..9}

答え2

POSIXツールでは、

find . -type f -exec sh -c 'for f; do dirn="${f%/*}"; mv -- "$f" "$dirn${f##*/}"; done' sh {} +

findシェルを起動し、各ファイルに対して for ループを実行します。

  • dirn="${f%/*}"ファイル名の最後のスラッシュ以降のすべてを除外して親ディレクトリ名を取得します。

  • ${f##*/}ファイル名の最後のスラッシュより前にあるもの (最後のスラッシュを含む) をすべて除外して、パスなしのファイル名を取得します。

これら2つのシェル構造は、dirnameそしてbasenameなので、このコマンドの同等の形式は次のようになります。

find . -type f -exec sh -c 'for f; do mv -- "$f" "$(dirname "$f")$(basename "$f")"; done' sh {} +

ただし、ファイルごとに 2 つの追加プロセスを生成する必要があるため、この方法は遅くなります。

例に示すように、複数のディレクトリに降りる必要がない場合は、単純なシェル ループでそれを実行します。

for f in */*; do dirn="${f%/*}"; echo mv -- "$f" "$dirn${f##*/}"; done

関連情報