Próbowałem .hgignore
dzisiaj szybko edytować plik z powłoki bash Cygwin i dodałem wiersz, który był błędem. Nie jestem pewien, czy to był najlepszy sposób, aby to zrobić, ale szybko pomyślałem o head -1 .hgignore
usunięciu linii obrażającej (wcześniej miałem tylko jedną linię w pliku). Rzeczywiście, po wykonaniu daje pierwszy wiersz jako jedyne wyjście.
Ale kiedy próbowałem przekierować dane wyjściowe i przepisać plik za pomocą head -1 .hgignore > .hgignore
, plik był pusty. Dlaczego to się dzieje? Jeśli spróbuję zamiast head -1 .hgignore >> .hgignore
tego dołączyć, to dodaje się poprawnie, ale to oczywiście nie jest pożądany wynik. Dlaczego przekierowanie obcinające nie działa w tym przypadku?
shell
io-redirection
voithos
źródło
źródło
cut
zmiany pliku na miejscu? , Jak sprawić, by iconv zastąpił plik wejściowy przekonwertowanym wyjściem?Odpowiedzi:
Gdy powłoka otrzyma wiersz poleceń, taki jak:
command > file.out
sama powłoka otwiera (i może tworzy) plik o nazwiefile.out
. Powłoka ustawia deskryptor pliku 0 na deskryptor pliku otrzymany z otwartej przestrzeni. Tak działa przekierowanie We / Wy: każdy proces wie o deskryptorach plików 0, 1 i 2.Trudność polega na tym, jak otworzyć
file.out
.file.out
Przez większość czasu chcesz otwierać do zapisu z przesunięciem 0 (tzn. Obcięte) i właśnie to zrobiła dla ciebie powłoka. Skrócił plik .hgignore, otworzył go do zapisu, skopiował deskryptor plików do 0, a następnie wykonałhead
. Natychmiastowe blokowanie plików.W powłoce bash możesz
set noclobber
zmienić to zachowanie.źródło
Myślę, że Bruce odpowiada na to, co się tu dzieje z rurociągiem pocisków.
Jednym z moich ulubionych małych narzędzi jest
sponge
polecenie moreutils . Rozwiązuje dokładnie ten problem, „wchłaniając” wszystkie dostępne dane wejściowe przed otwarciem docelowego pliku wyjściowego i zapisaniem danych. Umożliwia pisanie potoków dokładnie tak, jak się spodziewałeś:Rozwiązaniem biednego człowieka jest potokowanie wyjścia do pliku tymczasowego, a następnie po zakończeniu potoku (na przykład następnego uruchomionego polecenia) przeniesienie pliku tymczasowego z powrotem do pierwotnej lokalizacji pliku.
źródło
head -1 .hgignore | tee .hgignore
?tee
jest w coreutils, i jako efekt / efekt uboczny, to również pisze STDOUTtee
otwiera i obcina plik, do którego zapisuje, gdy jest tworzony, podobnie jak wszystko inne, więc nie rozwiązuje on głównego problemu warunków wyścigu podczas czytania zawartości pliku przed obcięciem go przy zapisie.tee
wydaje się, że robię to, czego pragnę . Mam wersję8.13
na moim komputerze.tee
Program będzie obciąć swoje pliki, nie jest ustawiony tak, aby podwoić bufor nich.W
file
jest obcinany przedhead
uruchomieniem, ale jeśli go napiszesz:nie jest tak, jak
file
jest otwarty w trybie do odczytu i zapisu. Jednak pohead
zakończeniu pisania plik nie jest obcinany, więc powyższa linia niehead
byłaby dostępna ( po prostu przepisałaby pierwszą linię nad sobą i pozostawiła pozostałe bez zmian).Jednak po
head
powrocie i gdyfd
nadal jest otwarty, możesz wywołać inne polecenie, które wykonujetruncate
.Na przykład:
Ważne jest to, że
truncate
powyżej,head
po prostu przesuwa kursor dla fd 1 wewnątrz pliku tuż po pierwszym wierszu. Przepisuje pierwszą linię, której nie potrzebowaliśmy, ale to nie jest szkodliwe.Dzięki głowicy POSIX moglibyśmy uciec bez przepisywania pierwszej linii:
W tym przypadku wykorzystujemy fakt, że
head
przesuwa pozycję kursora w jego standardowe wejście. Podczas gdyhead
zwykle czytałby swoje dane wejściowe dużymi fragmentami, aby poprawić wydajność, POSIX wymagałby (tam, gdzie to możliwe)seek
cofnięcia się zaraz po pierwszym wierszu, jeśli przekroczyłby go. Należy jednak pamiętać, że nie wszystkie implementacje to robią.Alternatywnie możesz
read
zamiast tego użyć polecenia powłoki :źródło
STDIN
podobnie do tego, co osiągnąłeśperl
powyżejdd
może jednak obciąć dowolny dowolny bezwzględny offset w pliku. Możesz więc ustalić przesunięcie bajtu drugiej linii i stamtąd stamtąd za pomocądd bs=1 seek="$offset" of=file
Rozwiązaniem Prawdziwego Człowieka jest
lub jako jedna linijka
Lub z GNU sed:
(Nie, żartuję. Użyłbym interaktywnego edytora.
vi .hgignore
GddZZ
)źródło
:wq
nadZZ
?:x
co robią moje palce automatycznieZQ
jest taki sam jak:q!
Możesz używać Vima w trybie Ex:
2,
zaznacz linie 2 do końcad
usunąćx
Zapisz i zamknijźródło
Do edycji plików w miejscu możesz także użyć sztuczki z otwartym uchwytem pliku, jak Jürgen Hötzel w danych wyjściowych Przekieruj z sed 's / c / d /' myFile do myFile .
źródło
rm .hgignore
Twoja moc zawiedzie, zabierając godziny ciężkiej pracy. Ok, to nie ma znaczenia.hgignore
, ale dlaczego miałbyś zrobić coś tak skomplikowanego? Tak więc moja opinia negatywna: technicznie poprawna, ale bardzo zły pomysł.perl -i
(w przypadku edycji w miejscu) i nie byłbym zaskoczony, gdyby niektóre implementacjesed -i
również to zrobiły (choćsed
wydaje się, że nie jest to najnowsza wersja GNU ).