Hasilkan nama baru untuk file yang dipindahkan untuk mencegah penulisan ulang?

8

Bagaimana saya bisa menghasilkan nama baru untuk file jika ada file yang sudah ada Dengan nama yang sama? Di lingkungan Desktop, nama baru dihasilkan, saya menambahkan nomor ke akhir nama file, tetapi bagaimana ini bisa dilakukan dari baris perintah?

Saya menggunakan sistem operasi Android dengan Busybox.

kyle k
sumber
1
Bisakah Anda memperluas Q Anda untuk menentukan dalam kapasitas apa Anda ingin membuat file-file ini sehubungan dengan Android? Jawa? Perkakas apa yang Anda miliki, busybox? Atau hanya vanilla android?
slm
@ pengguna slm Saya akan menggunakannya untuk membuat cadangan file yang terdapat dalam folder unduhan di tablet saya, program mengurutkan file berdasarkan ekstensi ke folder masing-masing di sana, saya telah menulis skrip python yang melakukan ini, tetapi program lambat dan juga menimpa file jika memiliki nama yang sama. Saya sedang dalam proses menulis ulang program menjadi bash, menghasilkan nama baru adalah bagian yang saya perjuangkan.
kyle k
Terima kasih atas jawabannya! Apakah Anda memiliki akses ke versi mktemp?
slm
@ pengguna slm Saya telah menginstal busybox dan sudah termasuk, tetapi jika saya melakukan panggilan sistem dari suatu program mktemptidak akan berfungsi.
kyle k
Tidak berfungsi dengan beberapa jenis kesalahan? Dari mana Anda membuat panggilan sistem ini? Python?
slm

Jawaban:

5

Dengan asumsi Anda memiliki shell POSIX, Anda dapat melakukan ini:

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
}

Cara menggunakan ini

Ini adalah fungsi jadi simpan di Anda ~/.bashrcdan menyebutnya seperti biasa mv.

Apa ini?

  • Menyimpan path ke mvexecutable asli dalam MVvariabel
  • Mendapat argumen terakhir yang dipanggil dengan variabel DEST
  • Jika DESTada dan bukan direktori, fungsi ini mengasumsikan bahwa nama Anda sedang mencoba untuk memecahkan suatu file
  • Kemudian ekstrak awalan nama akhir (apa pun sebelum final ., yang menandai ekstensi), ekstensi (apa pun setelah final .), jumlah (jika ada; apa pun di awalan setelah final -).
  • Jumlah yang diekstraksi diatur ke nol jika tidak ada jumlah yang ditemukan, itu ditetapkan ke jumlah yang ditemukan pada langkah sebelumnya.
  • Hitungan saat ini bertambah
  • Fungsi ini kemudian memanggil dirinya sendiri dengan semua argumen asli (beralih + nama file) minus yang terakhir dan menambahkan nama file baru alih-alih argumen terakhir dalam panggilan asli. Nama baru adalah nama lama tetapi dengan penghitung 3 digit (tanpa isian nol) ditambahkan sebelum ekstensi.
  • Fungsi ini bersifat rekursif karena jika Anda mengatakannya mv a.txt b.txtakan terlebih dahulu mencoba mv a.txt b-001.txt. mvPanggilan selanjutnya ini juga harus merupakan fungsi itu sendiri karena jika b-001.txtjuga ada, kami ingin terus menambah penghitung hingga kami menemukan nama file baru yang tidak ada.
  • Jika argumen terakhir tidak ada atau direktori, mvexecutable asli dipanggil dengan argumen asli Anda.

Peringatan

  • Jumlah kali Anda dapat berulang kali mencoba untuk memecahkan file yang ada tergantung pada panjang penghitung (999 kali dalam kasus ini). Anda dapat memilih sejumlah digit yang mencakup batas inode pada sistem file Anda untuk memastikan bahwa ini akan berfungsi selama Anda dapat membuat file.
  • Jika Anda mencoba clobber file yang namanya mirip foo-001.txt, itu akan dipindahkan ke foo-001-001.txt.

Catatan

  • Untuk mengubah pola penamaan, mengubah 3dalam printfpernyataan kepada apa pun yang Anda suka.
  • Kode ini telah diuji
  • Ini sangat sederhana dan saya yakin akan ada kasus tepi di mana gagal total. Saya senang mencoba dan memperbaikinya untuk Anda jika Anda menemukannya. Sementara itu, jangan coba ini menggunakan mesin produksi.
Joseph R.
sumber
pikiran yang sama di sini: P
Rahul Patil
@RahulPatil Kecuali saya mencoba menduplikasi perilaku GUI.
Joseph R.
itu bagus, saya belum menggunakan GUI.
Rahul Patil
itu menimpa file tujuan jika keluar, saya telah menguji paste.ubuntu.com/6071897
Rahul Patil
@RahulPatil Tidak yakin apa yang Anda katakan: dalam contoh Anda, ini mengidentifikasi bahwa itu /tmpadalah direktori yang ada dan disebut /bin/mv file1 /tmpSaya tidak melihat di mana masalahnya.
Joseph R.
3

Saya biasanya menggunakan alat ini mktempuntuk membuat file sementara yang andal. Ini default untuk membuat file, tetapi juga dapat membuat direktori juga, melalui -dperalihannya.

Contoh

Inilah cara Anda dapat membuat beberapa nama sementara ke file di direktori Anda saat ini.

$ mktemp somefile.XXXXX
somefile.kiDad

$ mktemp somefile.XXXX
somefile.MrSW

$ mktemp someotherfile.XXXXXXXXXXX
someotherfile.Um4aXKrt3lv

Ini akan membuat file untuk Anda.

Referensi

slm
sumber
2
Tidak mktempdi Android, tetapi +1 dari saya tetap karena ini adalah jawaban yang bagus untuk pertanyaan yang bagus, bijak U&L.
goldilocks
@goldilocks - terima kasih atas kata-kata baik Anda. Selalu menyenangkan!
slm
@goldilocks - tahukah Anda jika busybox disertakan? Ada implementasi mktemp dalam hal itu, saya tidak tahu banyak tentang android. code.google.com/p/abb/source/browse/mktemp.c?name=upstream/…
slm
1
Sepertinya busybox di android mengharuskan perangkat di-root (jailbroken). Shell asli adalah /system/bin/shdan tampaknya shkompatibel - dibangun seperti if [ -w $file ]pekerjaan, mvdan renametersedia - sehingga skrip untuk melakukan ini hanya dengan built-in harus bekerja di sana.
goldilocks
@goldilocks - terima kasih telah memeriksa. Apa yang Anda cari untuk mengetahui ini? Saya ingin agar kaki saya basah dengan Android tetapi tidak ingin memiliki telepon / perangkat.
slm
2

Ini adalah alternatif dari naskah Joseph R yang tidak memiliki peringatan! Ini akan menambahkan sufiks numerik ke nama path (path bisa berupa direktori atau file), menambah nilai sufiks hingga ditemukan yang belum ada. Utilitas lain seperti logrotatemenggunakan pola yang sama, tetapi memutar semua salinan yang ada sehingga yang baru selalu memiliki '0' untuk sufiks. Karena ini bukan rotasi dalam arti itu, saya akan menyebutnya dotmv. Ingatlah bahwa itu file.0akan menjadi salinan tertua .

Sebagai contoh:

dotmv somefile.txt

Ganti nama somefile.txt somefile.txt.0, kecuali yang terakhir ada, dalam hal ini akan terjadi somefile.txt.1, dan seterusnya. Anda dapat membuat daftar lebih dari satu file ( dotmv this that "the other thing"dll.), Semuanya akan dipindahkan dari titik.

Saya percaya ini kompatibel dengan POSIX - ini berjalan dengan set -o posixdi bash (tapi itu adalah tes yang meragukan). Saya juga diuji dengan shell android (jelly bean 4.2.1), dan berfungsi di sana. Namun, di android Anda harus mengubah shebang seperti yang ditunjukkan atau menjalankannya sh dotmv- yang mana Anda akan lakukan kecuali Anda memiliki perangkat yang telah di-rooting, karena tidak ada cara untuk membuat skrip dapat dieksekusi sebaliknya. Mengubah shebang akan memungkinkan Anda untuk menggunakannya 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

Semoga logika di sini sangat mudah. Ini dapat diimplementasikan dalam python, C, atau bahasa prosedural lengkap turing lainnya dengan file I / O.

goldilocks
sumber