GNU/Linux >> Znalost Linux >  >> Linux

Vytvořte nový soubor, ale přidejte číslo, pokud název souboru již v bash existuje

Aby se vyhnuli podmínkám závodu :

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

A navíc máte soubor otevřený pro zápis na fd 3.

S bash-4.4+ , můžete z něj vytvořit funkci jako:

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
}

K použití například jako:

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

max hodnotu lze použít k ochraně před nekonečnými smyčkami, když soubory nelze vytvořit z jiného důvodu než noclobber .

Všimněte si, že noclobber platí pouze pro > operátor, nikoli >> ani <> .

Zbývající závodní stav

Vlastně noclobber neodstraní spor ve všech případech. Zabraňuje pouze pravidelnému ucpání soubory (nikoli jiné typy souborů, takže cmd > /dev/null například neselže) a má ve většině shellů samotný závod.

Shell nejprve provede stat(2) na souboru zkontrolovat, zda se jedná o běžný soubor nebo ne (fifo, adresář, zařízení...). Pouze v případě, že soubor (zatím) neexistuje nebo jde o běžný soubor, 3> "$file" použijte příznak O_EXCL, abyste zaručili, že soubor nebude clobován.

Pokud tedy existuje soubor fifo nebo zařízení s tímto názvem, bude použit (za předpokladu, že jej lze otevřít pouze pro zápis), a běžný soubor může být zablokován, pokud bude vytvořen jako náhrada za fifo/zařízení/adresář. .. mezi tím stat(2) a open(2) bez O_EXCL!

Změna

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

do

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

Vyhnulo by se použití již existujícího neobvyklého souboru, ale neřešilo spor.

Nyní je to opravdu problém tváří v tvář zlomyslnému protivníkovi, který by vás chtěl přimět přepsat libovolný soubor v systému souborů. Odstraní spor v normálním případě dvou instancí stejného skriptu spuštěného ve stejnou dobu. V tom je tedy lepší než přístupy, které pouze předem ověřují existenci souboru pomocí [ -e "$file" ] .

Pro pracovní verzi bez sporu můžete použít zsh shell místo bash který má nezpracované rozhraní na open() jako sysopen vestavěný v zsh/system modul:

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

Jednodušší:

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

Získáte:

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

Následující skript vám může pomoci. Neměli byste spouštět několik kopií skriptu současně, abyste se vyhnuli sporu.

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. atomic create soubor, pokud neexistuje z bash skriptu

  2. přidat řádek do souboru POUZE pokud v souboru již není

  3. <název-služby> je mrtvý, ale soubor pid existuje

  1. Chybí vám nový soubor v Ubuntu 13.04?

  2. Jak v Bash přidám řetězec za každý řádek v souboru?

  3. Soubor služby existuje, ale nebyl nalezen systémem systemd

  1. Přidání časového razítka k názvu souboru s mv v BASH

  2. Jak zahrnout soubor do skriptu bash shell

  3. Jak přidat ikonu do výzvy bash