同じ名前の既存のファイルがある場合、どうすればファイルの新しい名前を生成できますか?デスクトップ環境では、ファイル名の末尾に番号を追加して新しい名前が生成されますが、これをコマンドラインから実行するにはどうすればよいですか?
BusyboxでAndroidオペレーティングシステムを使用しています。
POSIXシェルがあると仮定すると、次のことができます。
mv() {
eval "DEST=\${$#}" #The destination is the last positional parameter
if [ -e "$DEST" ] && ! [ -d "$DEST" ];then
PREFIX=${DEST%.*}
COUNT=1
EXT=${DEST##*.}
args= i=1
while [ $i -lt $# ]; do args="$args \"\${$i}\"" i=$((i+1)); done
DEST="$NAME-"$(printf "%03d" $COUNT)".$EXT"
while [ -e "$DEST" ];do
COUNT=$((COUNT+1))
DEST="$NAME-"$(printf "%03d" $COUNT)".$EXT"
done
eval "command mv $args \"\$DEST\""
else
command mv "$@"
fi
}
これの使い方
これは関数なので、~/.bashrc
に保存し、通常のmv
と同じように呼び出します。
これは何をするのか
mv
実行可能ファイルへのパスをMV
変数に格納しますDEST
に取得しますDEST
が存在し、ディレクトリではない場合、この関数は、名前変更がファイルを破壊しようとしていると想定します.
の前のすべて)、拡張子(最後の.
の後のすべて)、カウント(存在する場合、プレフィックス内の何か最終-
)。mv a.txt b.txt
と言った場合、最初にmv a.txt b-001.txt
を試行するため、この関数は再帰的です。この次のmv
呼び出しも関数自体である必要があります。これは、b-001.txt
も存在する場合、存在しない新しいファイル名が見つかるまでカウンターをインクリメントし続けるためです。mv
実行可能ファイルが元の引数で呼び出されます。警告
foo-001.txt
に似ているファイルをクローバーしようとすると、そのファイルはfoo-001-001.txt
に移動されます。メモ
printf
ステートメントの3
を好きなように変更します。私は通常、ツールmktemp
を使用して信頼できる一時ファイルを作成します。デフォルトではファイルの作成になりますが、-d
スイッチを使用してディレクトリを作成することもできます。
現在のディレクトリ内のファイルに一時的な名前を作成する方法は次のとおりです。
$ mktemp somefile.XXXXX
somefile.kiDad
$ mktemp somefile.XXXX
somefile.MrSW
$ mktemp someotherfile.XXXXXXXXXXX
someotherfile.Um4aXKrt3lv
これにより、ファイルが作成されます。
これは、警告のないジョセフRのスクリプトの代替です!パス名に数値のサフィックスを追加し(パスはディレクトリまたはファイルにすることができます)、まだ存在していないサフィックス値が見つかるまでサフィックス値をインクリメントします。 logrotate
などの他のユーティリティも同様のパターンを使用しますが、既存のすべてのコピーをローテーションして、新しいコピーのサフィックスが常に「0」になるようにします。その意味ではローテーションではないので、dotmv
と呼びます。 file.0
が最も古いコピーになることを覚えておいてください。
例えば:
dotmv somefile.txt
somefile.txt
somefile.txt.0
の名前を変更します。ただし、後者が存在する場合は、somefile.txt.1
などになります。複数のファイル(dotmv this that "the other thing"
など)をリストすることができ、それらはすべてドット移動されます。
これはPOSIXに準拠していると思います。bashではset -o posix
で実行されます(ただし、これは疑わしいテストです)。 Android(Jelly bean 4.2.1)シェルでもテストしましたが、そこで動作します。ただし、Androidでは、シバンを次のように変更する必要があります。 sh dotmv
を指定または実行します。これは、ルート化されたデバイスがない限り、スクリプトを実行可能にする方法がないためです。Shebangを変更すると、exec dotmv
を使用できるようになります。
#!/bin/sh
# On Android change that to /system/bin/sh.
# Validate arguments
if [ $# -lt 1 ]; then
echo "A list of one or more paths is required."
exit 1
fi
# Checks if a path exists and can be moved.
checkPath () {
if [ ! -e "$1" ]; then
echo "'$1' does not exist."
return 1;
fi
if [ ! -w "$1" ]; then
echo "Cannot move '$1', permission denied."
return 1;
fi
return 0;
}
# Finds a new path with numerical suffix.
getName () {
suf=0;
while [ -e "$1.$suf" ]
do let suf+=1
done
Dest=$1.$suf
}
# Loop through arguments -- use quotes to allow spaces in paths.
while (($#)); do
Src=$1
Dest=$1
shift
checkPath "$Src"
if [ $? -eq 0 ]; then
getName "$Src"
mv "$Src" "$Dest"
fi
done
うまくいけば、ここでのロジックは非常に単純です。これは、Python、C、またはファイルI/Oを使用したその他のチューリング完全な手続き型言語で実装できます。