上書きを防ぐために、移動したファイルの新しい名前を生成しますか?

上書きを防ぐために、移動したファイルの新しい名前を生成しますか?

同じ名前の既存のファイルがある場合は、ファイルの新しい名前を生成する方法は?デスクトップ環境では、ファイル名の末尾に数字を追加して新しい名前を生成しますが、コマンドラインではどのようにこれを実行できますか?

私はAndroid OSとBusyboxを使用しています。

答え1

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、この関数は名前変更がファイルを破損しようとしていると仮定します。
  • 次に、最終名の接頭辞(最終名の前のすべての項目.、拡張子の表示)、拡張子(最終名の後のすべての項目.)、数(存在する場合は最終名の後の接頭辞のすべての項目-)を抽出します。
  • 抽出された数は、数がない場合は0に設定され、それ以外の場合は前のステップで見つかった数に設定されます。
  • 現在のカウント増加
  • その後、関数はすべての元の引数(スイッチ+ファイル名)から最後の引数を引いた値で自分自身を呼び出し、元の呼び出しの最後の引数の代わりに新しいファイル名を追加します。新しい名前は古い名前ですが、拡張子の前に3桁のカウンターが追加されます(ゼロパディング)。
  • 関数は再帰的です。なぜなら、次の呼び出しは関数自体でなければならないからです。関数が存在する場合は、存在しない新しいファイル名が見つかるまでカウンタを増やし続けようとするためですmv a.txt b.txtmv a.txt b-001.txtmvb-001.txt
  • 最後の引数が存在しない場合、またはディレクトリの場合、元の実行可能mvファイルは元の引数を使用して呼び出されます。

ガイドライン

  • 既存のファイルを破損しようと繰り返し試行できる回数は、カウンタの長さによって異なります(この場合は999回)。ファイルの作成中に動作させるには、ファイルシステムのinode制限を含む数値を選択できます。
  • と同様の名前のファイルを破損しようとするとfoo-001.txtfoo-001-001.txt

ノート

  • 命名パターンを変更するには、文を必要に応じて3変更します。printf
  • このコードはテストされました。
  • これは非常に簡単で、いくつかの極端なケースではひどく失敗すると確信しています。問題が見つかったら、喜んで解決させていただきます。また、本番システムではこれを試みないでください。

答え2

私は通常このツールを使用して安定した一時mktempファイルを作成します。デフォルトではファイルを作成しますが、スイッチを介して-dディレクトリを作成することもできます。

はい

現在のディレクトリにあるファイルの一時的な名前を作成する方法は次のとおりです。

$ mktemp somefile.XXXXX
somefile.kiDad

$ mktemp somefile.XXXX
somefile.MrSW

$ mktemp someotherfile.XXXXXXXXXXX
someotherfile.Um4aXKrt3lv

これによりファイルが生成されます。

引用する

答え3

警告なしにJosephのRスクリプトに代わるものがあります!パス名に数字のサフィックスを追加し(パスはディレクトリまたはファイルにすることができます)、まだ存在しないサフィックスが見つかるまでサフィックスの値を増やします。logrotate同様のパターンを使用しますが、新しいコピーのサフィックスが常に「0」になるように既存のコピーをすべて回転させるなどのその他のユーティリティもあります。これはそういう意味で回転じゃないからと呼びますdotmvfile.0最も古いコピー。

たとえば、

dotmv somefile.txt

rename somefile.txt somefile.txt.0、後者が存在しない限り、存在する場合には にsomefile.txt.1なります。複数のファイル(dotmv this that "the other thing"など)を一覧表示でき、すべてのファイルをクリックして移動します。

私はこれがPOSIXと互換性があると思います。これはset -o posixbashで実行されます(ただしこれはあいまいなテストです)。私もAndroid(jelly bean 4.2.1)シェルでテストし、そこで動作しました。ただし、Androidではshebangを変更または実行するには指示に従う必要があります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を含む他のTuring-completeプロシージャ言語で実装できます。

関連情報