GNU/Linux >> Linux Esercitazione >  >> Linux

Crea un nuovo file ma aggiungi il numero se il nome del file esiste già in bash

Per evitare le condizioni di gara :

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

Inoltre, hai il file aperto per la scrittura su fd 3.

Con bash-4.4+ , puoi renderlo una funzione come:

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
}

Da utilizzare ad esempio come:

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

Il max value può essere utilizzato per proteggersi da loop infiniti quando i file non possono essere creati per motivi diversi da noclobber .

Nota che noclobber si applica solo al > operatore, non >><> .

Condizioni di competizione rimanenti

In realtà, noclobber non rimuove la race condition in tutti i casi. Previene solo il clobbering normale file (non altri tipi di file, quindi cmd > /dev/null per esempio non fallisce) e ha una race condition stessa nella maggior parte delle shell.

La shell prima esegue un stat(2) sul file per verificare se si tratta di un file normale o meno (fifo, directory, dispositivo...). Solo se il file non esiste (ancora) o è un file normale 3> "$file" usa il flag O_EXCL per garantire di non danneggiare il file.

Quindi, se esiste un fifo o un file di dispositivo con quel nome, verrà utilizzato (a condizione che possa essere aperto in sola scrittura) e un file normale potrebbe essere cancellato se viene creato in sostituzione di un fifo/dispositivo/directory. .. tra quel stat(2) e open(2) senza O_EXCL!

Cambiare il

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

a

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

Eviterebbe di usare un file non regolare già esistente, ma non affronta la race condition.

Ora, questa è davvero una preoccupazione solo di fronte a un avversario malintenzionato che vorrebbe farti sovrascrivere un file arbitrario sul file system. Rimuove la condizione di competizione nel caso normale di due istanze dello stesso script in esecuzione contemporaneamente. Quindi, in questo, è meglio degli approcci che controllano solo l'esistenza del file in anticipo con [ -e "$file" ] .

Per una versione funzionante senza race condition, puoi usare zsh shell invece di bash che ha un'interfaccia grezza per open() come sysopen integrato nel zsh/system modulo:

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

Più facile:

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

Otterrai:

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

Il seguente script può aiutarti. Non dovresti eseguire più copie dello script contemporaneamente per evitare race condition.

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. Manca un nuovo file in Ubuntu 13.04?

  2. In Bash, come aggiungo una stringa dopo ogni riga in un file?

  3. Aggiunta di timestamp a un nome file con mv in BASH

  4. Come includere un file in uno script di shell bash

  5. Come aggiungere un'icona al prompt di bash

Come creare un nuovo file system Ext4 (partizione) in Linux

Come verificare se un file o una directory esiste in Bash

4 modi per creare un nuovo file in Linux

Come aggiungere un nuovo dispositivo al file system BTRFS in Linux

Opzione del menu contestuale di Nautilus per creare un nuovo file?

Come verificare se esiste un file o una directory in Bash Shell