2012-12-11 21 views
5

W wywołaniu systemowym open(), jeśli otworzę z O_CREAT | O_EXCL, wywołanie systemowe zapewnia, że ​​plik zostanie utworzony tylko wtedy, gdy nie istnieje. Atomowość jest gwarantowana przez wywołanie systemowe. Czy istnieje podobny sposób utworzenia pliku w sposób atomowy ze skryptu Bash?atomowy plik do utworzenia, jeśli nie istnieje ze skryptu Bash

UPDATE: znalazłem dwa różne sposoby atomowych

  1. Zastosowanie set -o noclobber. Następnie możesz użyć operatora atomowo.
  2. Po prostu użyj mkdir. Mkdir jest atomowy
+0

_The system gwarantuje, że plik zostanie utworzony tylko jeśli nie exist_ Hmpf. Jeśli plik nie istnieje, zostanie utworzony. Jeśli istnieje, wywołanie systemowe zakończy się niepowodzeniem. – pbhd

+0

Możesz wypróbować 'mktemp', aby utworzyć plik, a następnie spróbuj' mv' go do żądanej nazwy. –

Odpowiedz

17

w 100% czysty rozwiązanie bash:

set -o noclobber 
{ > file ; } &> /dev/null 

To polecenie tworzy plik o nazwie file jeśli nie ma pliku o nazwie file istnieje. Jeśli istnieje plik o nazwie file, a następnie zrobić nic (ale zwraca niezerowy kod zwrotny).

Plusy wrt polecenia touch:

  • nie aktualizuje znacznik czasu, jeśli plik już istnieje
  • 100% bash wbudowane
  • kod powrotu zgodnie z oczekiwaniami: jeśli nie istniała już file czy file mogłem” t być stworzone; sukces, jeśli file nie istnieje i został utworzony.

Wady:

  • należy ustawić opcję noclobber (ale to w porządku w skrypcie, jeśli jesteś ostrożny z przekierowaniami lub rozbrojony to później).

Domyślam się, że to rozwiązanie jest naprawdę odpowiednikiem bash połączenia systemowego open z O_CREAT | O_EXCL.

+0

+1 - Krótki i czysty. –

+2

Czy "> plik" jest gwarantowany jako atomowy? –

+0

'(zestaw -o noclobber;> plik) &>/dev/null' robi to samo, ale nie ma wpływu na opcję' noclobber' w bieżącej powłoce. –

-2

touch to polecenie, którego szukasz. Aktualizuje sygnatury czasowe podanego pliku, jeśli plik istnieje lub tworzy go, jeśli nie istnieje.

+3

Poza tym nie zawiedzie, gdy plik już istnieje, tak jak robi to O_EXCL. –

+0

Nie patrzyłem na źródło dotyku, ale nie może ono być atomowe. Otoh, zmienia zarówno czas dostępu, jak i modyfikacji, jeśli plik istnieje. –

+1

touch nie jest atomowy – Jimm

2

Dla jasności zapewnienie, że plik zostanie utworzony, tylko jeśli nie istnieje, to nie to samo co atomowość. Operacja jest atomowa wtedy i tylko wtedy, gdy dwa lub więcej oddzielnych wątków próbuje zrobić to samo w tym samym czasie, dokładnie jeden odniesie sukces, a wszystkie inne zawiedzie.

Najlepszym sposobem, wiem, aby utworzyć plik atomowo w skrypcie powłoki następuje tego wzorca (i to nie jest idealne):

  1. utworzyć plik, który ma bardzo dużą szansę na nieistniejące (przy użyciu przyzwoity wybór losowy numer lub coś w nazwie pliku), a następnie umieść jakieś unikalne treści w nim (coś, że żaden inny wątek nie miałby - znowu, liczba losowa lub coś)
  2. sprawdzić, czy plik istnieje i zawiera treść można oczekiwać to do
  3. utwórz twardy link z tego pliku do żądanego pliku
  4. zweryfikować, że żądany plik zawiera oczekiwanych zawartość

W szczególności touch nie jest atomowa, ponieważ będzie utworzyć plik, jeśli go tam nie ma, lub po prostu zaktualizować znacznik czasu. Możesz grać w gry z różnymi znacznikami czasu, ale czytanie i analizowanie znacznika czasu, aby sprawdzić, czy "wygrałeś" wyścig jest trudniejsze niż powyższe. mkdir może być atomowej, ale trzeba by sprawdzić kod zwrotny, bo w przeciwnym razie, można tylko powiedzieć, że „tak, katalog został stworzony, ale nie wiem, który wygrał gwint”. Jeśli jesteś na systemie plików, który nie obsługuje dowiązania twarde, może trzeba zadowolić się mniej idealnym rozwiązaniem.

2

Mogłeś go utworzyć pod losowo wygenerowaną nazwą, a następnie zmienić nazwę (mv -n random desired) na miejsce z żądaną nazwę. Zmiana nazwy zakończy się niepowodzeniem, jeśli plik już istnieje.

Jak to:

#!/bin/bash 

touch randomFileName 
mv -n randomFileName lockFile 

if [ -e randomFileName ] ; then 
    echo "Failed to acquired lock" 
else 
    echo "Acquired lock" 
fi 
+1

Moje "mv" nie jest atomowe. Najpierw używa "stat" do sprawdzenia, czy plik docelowy istnieje, a jeśli nie, używa "zmiany nazwy". Ale "zmiana nazwy" po prostu zastąpi cel, jeśli istnieje. Jest więc mały przedział czasowy (między wywołaniem "stat" a "zmień nazwę"), w którym plik utworzony z nazwą miejsca docelowego zostanie nadpisany. – SIGSEGV

+0

Ah, interesujące. 'mv' w ogóle nie pomoże, przepraszam. –

3

Oto funkcja bash pomocą mv -n trik:

function mkatomic() { 
    f="$(mktemp)" 
    mv -n "$f" "$1" 
    if [ -e "$f" ]; then 
    rm "$f" 
    echo "ERROR: file exists:" "$1" >&2 
    return 1 
    fi 
} 

Przykłady:

wezwanie
$ mkatomic foo 
$ wc -c foo 
0 foo 
$ mkatomic foo 
ERROR: file exists: foo 
Powiązane problemy