GNU/Linux >> Tutoriels Linux >  >> Linux

Créer un nouveau fichier mais ajouter un numéro si le nom de fichier existe déjà dans bash

Pour éviter les conditions de course :

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

Et en plus, vous avez le fichier ouvert en écriture sur fd 3.

Avec bash-4.4+ , vous pouvez en faire une fonction comme :

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
}

A utiliser par exemple comme :

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

Le max la valeur peut être utilisée pour se prémunir contre les boucles infinies lorsque les fichiers ne peuvent pas être créés pour une autre raison que noclobber .

Notez que noclobber ne s'applique qu'au > opérateur, pas >> ni <> .

Condition de concurrence restante

En fait, noclobber ne supprime pas la condition de concurrence dans tous les cas. Cela empêche seulement le clobbering régulier fichiers (pas d'autres types de fichiers, de sorte que cmd > /dev/null par exemple n'échoue pas) et a lui-même une condition de concurrence dans la plupart des shells.

Le shell fait d'abord un stat(2) sur le fichier pour vérifier s'il s'agit d'un fichier normal ou non (fifo, répertoire, périphérique...). Ce n'est que si le fichier n'existe pas (encore) ou s'il s'agit d'un fichier normal que 3> "$file" utilisez le drapeau O_EXCL pour garantir de ne pas encombrer le fichier.

Donc, s'il existe un fifo ou un fichier de périphérique portant ce nom, il sera utilisé (à condition qu'il puisse être ouvert en écriture seule), et un fichier normal peut être encombré s'il est créé en remplacement d'un fifo/device/directory. .. entre ces stat(2) et open(2) sans O_EXCL !

Changer le

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

à

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

Éviterait d'utiliser un fichier non régulier déjà existant, mais ne résoudrait pas la condition de concurrence.

Maintenant, ce n'est vraiment un problème que face à un adversaire malveillant qui voudrait vous faire écraser un fichier arbitraire sur le système de fichiers. Il supprime la condition de concurrence dans le cas normal de deux instances du même script s'exécutant en même temps. Donc, en cela, c'est mieux que les approches qui vérifient uniquement l'existence du fichier au préalable avec [ -e "$file" ] .

Pour une version de travail sans condition de concurrence, vous pouvez utiliser le zsh shell au lieu de bash qui a une interface brute vers open() comme le sysopen intégré dans le zsh/system modules :

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

Plus simple :

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

Vous obtiendrez :

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

Le script suivant peut vous aider. Vous ne devez pas exécuter plusieurs copies du script en même temps pour éviter les conditions de concurrence.

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. Dans Bash, comment ajouter une chaîne après chaque ligne dans un fichier ?

  2. Ajout d'horodatage à un nom de fichier avec mv dans BASH

  3. Comment inclure un fichier dans un script shell bash

  4. Comment ajouter une icône à l'invite bash

  5. fichier de création atomique s'il n'existe pas à partir du script bash

Comment créer un nouveau système de fichiers Ext4 (partition) sous Linux

Comment vérifier si un fichier ou un répertoire existe dans Bash

4 façons de créer un nouveau fichier sous Linux

Comment ajouter un nouveau périphérique au système de fichiers BTRFS sous Linux

Option de menu contextuel Nautilus pour créer un nouveau fichier ?

Comment vérifier si un fichier ou un répertoire existe dans Bash Shell