Python
Bash
Python3
Rename

bashで連番リネーム時の依存関係解決(Python3もある)

More than 1 year has passed since last update.

連番リネームの問題点

$ ls
0  1  2

な時に

0 -> 2
1 -> 3
2 -> 4

とリネームしたい時

$ mv 0 2
$ mv 1 3
$ mv 2 4

とすると
$ mv 0 220で上書きされて結果

$ ls
3 4

となってしまう.

bashの連想配列を使って依存関係を解決

※bashの連想配列はbash 4.x以降でしか使えません.
リネーム元とリネーム先の組み合わせは連想配列arrayに格納されているものとする.

rename.sh
#!/bin/bash

function output(){
    if ! [[ -z "${array[${array[$1]}]}" ]]; then
        output "${array[$1]}"
    fi
    echo mv "$1" "${array[$1]}"
    unset -v array[$1]
}

declare -A array

array=(
    [0]=2
    [1]=3
    [2]=4
)

for i in "${!array[@]}";do
    if ! [[ -z "${array[$i]}" ]]; then
        output "$i"
    fi
done

出力

mv 2 4
mv 0 2
mv 1 3

bashの連想配列の解法の問題点

"${array[${array[$1]}]}"

などがある為ファイルネームにスペースが含まれていると動かない.
頑張ってevalを使いまくればいけるかもしれない.

Python3で書くと

rename.py
#!/bin/python3

def output(item):
    if item[1] in array:
        output((item[1], array.pop(item[1])))
    print('mv "' + item[0] + '" "' + item[1] + '"')

array = {
    '0': '2',
    '1': '3',
    '2': '4',
}

while array:
    output(array.popitem())

# ファイル名に"が含まれている場合は以下
# print('mv "' + item[0].replace('"', '\\"') + '" "' +
#       item[1].replace('"', '\\"') + '"')

# 追記: $もエスケープしないといけなかった
# print('mv "' + item[0].replace('"', '\\"').replace('$', '\\$') + '" "' +
#       item[1].replace('"', '\\"') + '"').replace('$', '\\$')

出力

mv "2" "4"
mv "0" "2"
mv "1" "3"

出力は毎回異なるがmv "0" "2"は必ず最初でない.
これならスペースが含まれていても大丈夫.