パス名からファイル名と一番下のディレクトリ名を同時に抽出するワンライナー


動機

機械学習のデータセットを整理していたときに、
こういう構造のファイル群を

dir/
├── a/
│   ├── 0000.jpg
│   ├── 0001.jpg
│   ├── 0002.jpg
│   ︙
├── b/
│   ├── 0000.jpg
│   ├── 0001.jpg
│   ├── 0002.jpg
│   ︙
├── c/
│   ├── 0000.jpg
│   ├── 0001.jpg
│   ├── 0002.jpg
│   ︙

下のように、ディレクトリ名をファイル名の頭につけてコピーしたかった。

newdir/
├── a_0000.jpg
├── a_0001.jpg
├── a_0002.jpg
︙
├── b_0000.jpg
├── b_0001.jpg
├── b_0002.jpg
︙
├── c_0000.jpg
├── c_0001.jpg
├── c_0002.jpg
︙

方法

$ find ./dir -type f | xargs -L 1 -I {} sh -c 'echo {} | awk -F "/" '\''{print $(NF-1) "_" $(NF)}'\'''
出力
a_0000.jpg
a_0001.jpg
︙

findでとってきたパスをスラッシュで区切った後、最後から2番目の文字列(一番下のディレクトリ名)と最後の文字列(ファイル名)をアンダーバーで結合して表示する。
"/"の部分を他の文字に変えれば、異なる区切り文字にも対応できる。

コピーするときは、

$ find ./dir -type f | xargs -L 1 -I {} sh -c 'echo {} | awk -F "/" '\''{print $(NF-1) "_" $(NF)}'\''| { read newfn ; cp {} ./newdir/$newfn ; }'

とする。