GNU/Linux >> Tutoriales Linux >  >> Linux

Cree un nuevo archivo pero agregue un número si el nombre del archivo ya existe en bash

Para evitar las condiciones de carrera :

name=some-file

n=
set -o noclobber
until
  file=$name${n:+-$n}.ext
  { command exec 3> "$file"; } 2> /dev/null
do
  ((n++))
done
printf 'File is "%s"\n' "$file"
echo some text in it >&3

Y además, tienes el archivo abierto para escribir en fd 3.

Con bash-4.4+ , puede convertirlo en una función como:

create() { # fd base [suffix [max]]]
  local fd="$1" base="$2" suffix="${3-}" max="${4-}"
  local n= file
  local - # ash-style local scoping of options in 4.4+
  set -o noclobber
  REPLY=
  until
    file=$base${n:+-$n}$suffix
    eval 'command exec '"$fd"'> "$file"' 2> /dev/null
  do
    ((n++))
    ((max > 0 && n > max)) && return 1
  done
  REPLY=$file
}

Para ser utilizado por ejemplo como:

create 3 somefile .ext || exit
printf 'File: "%s"\n' "$REPLY"
echo something >&3
exec 3>&- # close the file

El max El valor se puede usar para protegerse contra bucles infinitos cuando los archivos no se pueden crear por otra razón que no sea noclobber .

Tenga en cuenta que noclobber solo se aplica al > operador, no >> ni <> .

Condición de carrera restante

En realidad, noclobber no elimina la condición de carrera en todos los casos. Solo previene palizas regular archivos (no otros tipos de archivos, por lo que cmd > /dev/null por ejemplo, no falla) y tiene una condición de carrera en la mayoría de los shells.

El shell primero hace un stat(2) en el archivo para verificar si es un archivo normal o no (fifo, directorio, dispositivo...). Solo si el archivo no existe (todavía) o es un archivo normal 3> "$file" use el indicador O_EXCL para garantizar que no se destruya el archivo.

Por lo tanto, si hay un archivo fifo o de dispositivo con ese nombre, se usará (siempre que se pueda abrir en modo de solo escritura), y un archivo normal puede verse afectado si se crea como reemplazo de un fifo/dispositivo/directorio. .. entre ese stat(2) y open(2) sin O_EXCL!

Cambiando el

  { command exec 3> "$file"; } 2> /dev/null

a

  [ ! -e "$file" ] && { command exec 3> "$file"; } 2> /dev/null

Evitaría usar un archivo no regular ya existente, pero no abordaría la condición de carrera.

Ahora, eso solo es realmente una preocupación frente a un adversario malicioso que querría hacerle sobrescribir un archivo arbitrario en el sistema de archivos. Elimina la condición de carrera en el caso normal de dos instancias del mismo script ejecutándose al mismo tiempo. Entonces, en eso, es mejor que los enfoques que solo verifican la existencia del archivo de antemano con [ -e "$file" ] .

Para una versión que funcione sin ninguna condición de carrera, puede usar el zsh shell en lugar de bash que tiene una interfaz sin formato para open() como el sysopen integrado en el zsh/system módulo:

zmodload zsh/system

name=some-file

n=
until
  file=$name${n:+-$n}.ext
  sysopen -w -o excl -u 3 -- "$file" 2> /dev/null
do
  ((n++))
done
printf 'File is "%s"\n' "$file"
echo some text in it >&3

Más fácil:

touch file`ls file* | wc -l`.ext

Obtendrás:

$ ls file*
file0.ext  file1.ext  file2.ext  file3.ext  file4.ext  file5.ext  file6.ext

El siguiente script puede ayudarte. No debe ejecutar varias copias del script al mismo tiempo para evitar la condición de carrera.

name=somefile
if [[ -e $name.ext || -L $name.ext ]] ; then
    i=0
    while [[ -e $name-$i.ext || -L $name-$i.ext ]] ; do
        let i++
    done
    name=$name-$i
fi
touch -- "$name".ext

Linux
  1. En Bash, ¿cómo agrego una cadena después de cada línea en un archivo?

  2. Agregar marca de tiempo a un nombre de archivo con mv en BASH

  3. Cómo incluir un archivo en un script de shell bash

  4. Cómo agregar un ícono al indicador de bash

  5. Cómo obtener solo el número de líneas de un archivo

Cómo crear un nuevo sistema de archivos Ext4 (partición) en Linux

Cómo verificar si existe un archivo o directorio en Bash

4 formas de crear un nuevo archivo en Linux

Cómo agregar un nuevo dispositivo al sistema de archivos BTRFS en Linux

¿Opción del menú contextual de Nautilus para crear un nuevo archivo?

Cómo verificar si existe un archivo o directorio en Bash Shell