¿Genera un nuevo nombre para el file movido para evitar la sobrescritura?

¿Cómo puedo generar un nuevo nombre para un file si hay un file con ese mismo nombre? En un entorno de escritorio, se genera un nuevo nombre al agregar un número al final del nombre del file, pero ¿cómo se puede lograr esto desde la command-line?

Estoy usando el sistema operativo Android con Busybox.

Solutions Collecting From Web of "¿Genera un nuevo nombre para el file movido para evitar la sobrescritura?"

Suponiendo que tiene un shell POSIX, puede hacer esto:

 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 } 

Como usar esto

Esta es una function así que guárdala en tu ~/.bashrc y ~/.bashrc como lo harías con el mv normal.

Que hace esto

  • Almacena la ruta al ejecutable mv original en la variable MV
  • Obtiene el último argumento con el que se DEST en la variable DEST
  • Si DEST existe y no es un directory, esta function asume que su cambio de nombre está tratando de destruir un file
  • Luego extrae el prefijo del nombre final (cualquier cosa antes del final . , Que marca la extensión), la extensión (cualquier cosa después del final), el recuento (si hay alguno, cualquier cosa en el prefijo después del final - ).
  • El recuento extraído se establece en cero si no se encontró recuento; de lo contrario, se establece en el recuento encontrado en el paso anterior.
  • El conteo actual se incrementa
  • La function luego se llama a sí misma con todos los arguments originales (interruptores + nombres de file) less la última y agrega el nuevo nombre de file en lugar del último argumento en la llamada original. El nuevo nombre es el antiguo, pero con un contador de 3 dígitos (sin relleno) agregado antes de la extensión.
  • La function es recursiva porque si estuviera diciendo mv a.txt b.txt , primero mv a.txt b-001.txt . Esta próxima llamada mv también debe ser la function en sí, porque si también existe b-001.txt , queremos seguir incrementando el contador hasta que encontremos un nuevo nombre de file que no existe.
  • Si el argumento final no existe o es un directory, se llama al ejecutable mv original con sus arguments originales.

Advertencias

  • El número de veces que puede intentar repetidamente tajear un file existente depende de la longitud del contador (999 veces en este caso). Puede elegir una cantidad de dígitos que abarque el límite de inode en su sistema de files para asegurarse de que funcionará mientras pueda crear files.
  • Si intenta interceptar un file cuyo nombre es similar a foo-001.txt , se moverá a foo-001-001.txt .

Notas

  • Para cambiar el patrón de nombre, cambie el 3 en la statement printf a lo que quiera.
  • Este código ha sido probado
  • Esto es muy simplist y estoy seguro de que habrá casos extremos en los que fracasará miserablemente. Me complace intentar solucionarlos si encuentra alguno. Mientras tanto, no intente esto en una máquina de producción.

Generalmente uso la herramienta mktemp para crear files temporales confiables. Por defecto, crea files, pero también puede crear directorys, a través de su -d .

Ejemplo

A continuación, le mostramos cómo puede crear algunos nombres temporales para los files en su directory actual.

 $ mktemp somefile.XXXXX somefile.kiDad $ mktemp somefile.XXXX somefile.MrSW $ mktemp someotherfile.XXXXXXXXXXX someotherfile.Um4aXKrt3lv 

Esto creará los files para ti.

Referencias

  • página man mktemp

¡Aquí hay una alternativa al guión de Joseph R que no tiene ninguna de las advertencias! Agregará un sufijo numérico a un nombre de ruta (la ruta puede ser un directory o un file), incrementando el valor del sufijo hasta que se encuentre uno que no exista. Otras utilidades como logrotate usan un patrón similar, pero rotan todas las copys existentes para que el nuevo siempre tenga '0' para un sufijo. Como esto no es una rotation en ese sentido, lo llamaré dotmv . Solo recuerde que file.0 será la copy más antigua .

Por ejemplo:

 dotmv somefile.txt 

somefile.txt somefile.txt.0 , a less que este último exista, en cuyo caso será somefile.txt.1 , y así sucesivamente. Puede listr más de un file ( dotmv this that "the other thing" etc.), todos ellos serán movidos por puntos.

Creo que esto es compatible con POSIX: se ejecuta con el set -o posix en bash (pero esa es una testing dudosa). También probé con el shell android (jelly bean 4.2.1), y funciona allí. Sin embargo, en Android necesitarás cambiar el shebang como se indica o ejecutarlo sh dotmv , que de todos modos a less que tengas un dispositivo rooteado, porque de lo contrario no hay forma de hacer un script ejecutable. Cambiar el shebang le permitirá usar 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 requinetworking." 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 

Espero que la lógica aquí sea muy directa. Esto podría implementarse en python, C o cualquier otro lenguaje de procedimiento completo con E / S de files.