Dlaczego przekierowanie pliku wyjściowego do samego siebie tworzy pusty plik?
Podane w Bash, dlaczego?
less foo.txt > foo.txt
i
fold foo.txt > foo.txt
produkować pusty foo.txt
? Ponieważ dodatek taki jak less eggs.py >> eggs.py
tworzy dwie kopie tekstu w eggs.py
, można oczekiwać, że nadpisanie spowoduje utworzenie jednej kopii tekstu.
Uwaga: nie mówię, że to błąd, bardziej prawdopodobne jest, że jest wskaźnikiem czegoś głębokiego w Uniksie.
bash
unix
unix-utils
marynarz
źródło
źródło
Odpowiedzi:
Podczas używania
>
plik jest otwierany w trybie obcięcia, więc jego zawartość jest usuwana, zanim polecenie spróbuje go odczytać.Podczas używania
>>
plik jest otwierany w trybie dołączania, aby istniejące dane zostały zachowane. W tym przypadku nadal jednak dość ryzykowne jest używanie tego samego pliku jako danych wejściowych i wyjściowych. Jeśli plik jest na tyle duży, że nie mieści się w rozmiarze bufora wejściowego do odczytu, jego rozmiar może rosnąć w nieskończoność, dopóki system plików nie zostanie zapełniony (lub osiągnięty zostanie limit miejsca na dysku).Jeśli chcesz użyć pliku jako danych wejściowych i wyjściowych z poleceniem, które nie obsługuje modyfikacji w miejscu, możesz zastosować kilka obejść:
Po zakończeniu użyj pliku pośredniego i zastąp oryginalny plik tylko wtedy, gdy nie wystąpi błąd podczas uruchamiania narzędzia (jest to najbezpieczniejszy i najczęstszy sposób).
Unikaj pliku pośredniego kosztem potencjalnej częściowej lub całkowitej utraty danych w przypadku wystąpienia błędu lub przerwy. W tym przykładzie zawartość pliku jest
foo.txt
przekazywana jako dane wejściowe do podpowłoki (w nawiasach) przed usunięciem pliku. Poprzedni i-węzeł pozostaje przy życiu, ponieważ podpowłoka utrzymuje ją otwartą podczas odczytu danych. Plik zapisany przez narzędzie wewnętrzne (tutajfold
) o tej samej nazwie (foo.txt
) wskazuje na inny i-węzeł, ponieważ stary wpis katalogu został usunięty, więc technicznie istnieją dwa różne „pliki” o tej samej nazwie podczas procesu. Po zakończeniu podpowłoki stary i-węzeł zostaje zwolniony, a jego dane utracone. Uważaj, aby upewnić się, że masz wystarczająco dużo miejsca, aby tymczasowo zapisać zarówno stary plik, jak i nowy w tym samym czasie, w przeciwnym razie stracisz dane.źródło
sponge
z moreutils może również pomóc.fold foo.txt | sponge foo.txt
- lubfold foo.txt | sponge !$
powinien również zrobić.Plik jest otwierany do zapisu przez powłokę, zanim aplikacja będzie mogła go odczytać. Otwarcie pliku do zapisu powoduje jego obcięcie.
źródło
W bash operator przekierowania strumienia
... > foo.txt
opróżnia sięfoo.txt
przed oceną lewego operandu .Można użyć podstawienia polecenia i wydrukować jego wynik jako obejście. To rozwiązanie wymaga mniej dodatkowych znaków niż w innych odpowiedziach:
Uwaga: to polecenie nie zachowuje żadnych nowych linii w
foo.txt
. Więcej informacji znajdziesz w sekcji komentarzy poniżejW tym przypadku podpowłoka
$(...)
jest oceniana przed operatorem przekierowania strumienia>
, stąd zachowanie informacji.źródło
tmp=$(cmd; printf q); printf '%s' "${tmp%q}"
. Ale z tą odpowiedzią pominąłeś inny problem: mówi „podpowłoka”, gdy oznacza „zastępowanie poleceń”. Tak, podstawienia poleceń są ogólnie podpowłokami, ale nie odwrotnie, a podpowłoki ogólnie nie pomagają w rozwiązaniu tego problemu.