Powszechnie wiadomo, że takie polecenie:
cat filename | some_sed_command >filename
usuwa nazwę pliku, ponieważ przekierowanie wyjścia, wykonywane przed poleceniem, powoduje obcięcie nazwy pliku.
Problem można rozwiązać w następujący sposób:
cat file | some_sed_command | tee file >/dev/null
ale nie jestem pewien, czy i tak to zadziała: co się stanie, jeśli plik (i wynik polecenia sed) jest bardzo duży? Jak system operacyjny może uniknąć zastąpienia niektórych treści, które wciąż nie są czytane? Widzę, że istnieje również polecenie gąbki, które powinno działać w każdym przypadku: czy jest „bezpieczniejsze” niż tee?
command-line
bash
tee
VeryHardCoder
źródło
źródło
Odpowiedzi:
Nie .
Szanse
file
zostaną obcięte, ale nie ma gwarancji,cat file | some_sed_command | tee file >/dev/null
że nie zostaną obciętefile
.Wszystko zależy od tego, które polecenie jest przetwarzane jako pierwsze, w przeciwieństwie do tego, czego można się spodziewać, polecenia w potoku nie są przetwarzane od lewej do prawej . Nie ma gwarancji, które polecenie zostanie wybrane jako pierwsze, więc równie dobrze można pomyśleć o tym, że zostało ono wybrane losowo i nigdy nie polegać na tym, że pocisk nie wybierze obrażającego.
Ponieważ szanse na wybranie obrażającego polecenia jako pierwszego spośród trzech poleceń są mniejsze niż szanse na wybranie obrażającego polecenia jako pierwszego pomiędzy dwoma poleceniami, jest mniej prawdopodobne, że
file
zostanie ono obcięte, ale nadal tak się stanie .script.sh
:Więc nigdy nie używaj czegoś takiego
cat file | some_sed_command | tee file >/dev/null
. Użyjsponge
zgodnie z sugestią Oli.Alternatywnie, w środowiskach o większym rozmiarze i / lub stosunkowo małych plikach można użyć łańcucha tutaj i podstawienia polecenia, aby odczytać plik przed uruchomieniem dowolnego polecenia:
źródło
W
sed
szczególności możesz użyć-i
argumentu na miejscu. Po prostu zapisuje z powrotem do pliku, który otworzył, np .:Jeśli chcesz zrobić coś mocniejszego, zakładając, że robisz więcej niż
sed
, tak, możesz buforować całość za pomocąsponge
(zmoreutils
pakietu), który „wchłonie” wszystkie standardowe wejścia przed zapisaniem do pliku. To tak,tee
ale z mniejszą funkcjonalnością. Jednak w przypadku podstawowego zastosowania jest to raczej wymiana zastępcza:Czy to jest bezpieczniejsze? Zdecydowanie. Prawdopodobnie ma ograniczenia, więc jeśli robisz coś kolosalnego (i nie możesz edytować w miejscu za pomocą sed), możesz chcieć dokonać edycji drugiego pliku, a następnie
mv
tego pliku z powrotem do oryginalnej nazwy pliku. To powinno być atomowe (więc wszystko, co zależy od tych plików, nie ulegnie awarii, jeśli będą potrzebować stałego dostępu).źródło
Możesz używać Vima w trybie Ex:
%
wybierz wszystkie linie!
Uruchom poleceniex
Zapisz i wyjdźźródło
Och, ale
sponge
to nie jedyna opcja; nie musisz tego robićmoreutils
, aby to działało poprawnie. Każdy mechanizm będzie działał, o ile spełnia następujące dwa wymagania:Widzisz, dobrze znanym problemem, do którego odnosi się OP, jest to, że powłoka utworzy wszystkie pliki, które są niezbędne do działania potoków, zanim zaczną nawet wykonywać polecenia w potoku, więc to powłoka faktycznie obcina plik wyjściowy (który niestety jest również plikiem wejściowym), zanim którekolwiek z poleceń zdążyło się uruchomić.
tee
Komenda nie działa, mimo że spełnia pierwszy warunek, ponieważ nie spełnia drugi warunek: będzie zawsze natychmiast utworzyć plik wyjściowy przy starcie, więc jest to w istocie tak źle, jak tworząc rurę prosto do pliku wyjściowego. (Jest tak naprawdę gorzej, ponieważ jego użycie wprowadza niedeterministyczne losowe opóźnienie przed obcięciem pliku wyjściowego, więc możesz pomyśleć, że działa, podczas gdy w rzeczywistości nie działa).Aby rozwiązać ten problem, potrzebujemy tylko polecenia, które zbuforuje wszystkie dane wejściowe przed wygenerowaniem danych wyjściowych i które jest w stanie zaakceptować nazwę pliku wyjściowego jako parametr, dzięki czemu nie musimy przesyłać danych wyjściowych do plik wyjściowy. Jednym z takich poleceń jest
shuf
. Tak więc następujące rzeczy osiągną to samo,sponge
co:W
--random-source=/dev/zero
części sztuczkishuf
język robi jego rzecz bez jakiegokolwiek szuranie w ogóle, więc będzie buforować swój wkład bez zmieniania go.źródło