Piszę skrypty powłoki dla mojego serwera, który jest hostem współdzielonym z systemem FreeBSD. Chcę też móc przetestować je lokalnie na komputerze z systemem Linux. Dlatego staram się pisać je w przenośny sposób, ale sed
nie widzę sposobu, aby to zrobić.
Część mojej strony używa generowanych statycznych plików HTML, a ta linia sed wstawia poprawny DOCTYPE po każdej regeneracji:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Działa z GNU sed
w systemie Linux, ale FreeBSD sed
oczekuje, że pierwszym argumentem po -i
opcji będzie rozszerzenie kopii zapasowej. Tak to wyglądałoby:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Jednak GNU sed
z kolei oczekuje, że wyrażenie pojawi się natychmiast po nim -i
. (Wymaga to również poprawek z obsługą nowego wiersza, ale na to już tutaj odpowiedziano )
Oczywiście mogę dołączyć tę zmianę do mojej kopii skryptu na serwerze, ale to by popsuło, tj. Moje użycie VCS do wersji. Czy istnieje sposób, aby to osiągnąć za pomocą sed w pełni przenośny sposób?
-i
Odpowiedzi:
GNU sed akceptuje opcjonalne rozszerzenie po
-i
. Rozszerzenie musi być w tym samym argumencie bez spacji. Ta składnia działa również na BSD sed.Zauważ, że w BSD
-i
zmienia również zachowanie, gdy istnieje wiele plików wejściowych: są one przetwarzane niezależnie (więc np.$
Dopasowuje ostatni wiersz każdego pliku). Również to nie będzie działać w BusyBox.Jeśli nie chcesz używać plików kopii zapasowych, możesz sprawdzić, która wersja sed jest dostępna.
Lub alternatywnie, aby uniknąć blokowania parametrów pozycji, zdefiniuj funkcję.
Jeśli nie chcesz się tym przejmować, użyj Perla.
Jeśli chcesz napisać przenośny skrypt, nie używaj
-i
go - nie ma go w POSIX. Rób ręcznie to, co robi sed pod maską - to tylko jeden wiersz kodu.źródło
sed -i
również implikuje-s
. Najłatwiejszym sposobem sprawdzenia GNUsed
jestsed v
użycie polecenia, które jest prawidłowym noop dla GNU, ale zawodzi wszędzie indziej.sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file"
jeśli nie jest to GNU sed, wstawia spację, po której następują dwa pojedyncze cytaty-i
, aby działa na BSD. GNU sed dostaje tylko-i
.v
polecenia do testowania GNU sed. Co jeśli FreeBSD zdecyduje się go wdrożyć?sed v
biorąc pod uwagę, że taki jest cel istnienia.Jeśli nie znajdziesz sposobu na uprzyjemnienie
sed
gry, możesz spróbować:Nie używaj
-i
:Użyj Perla
źródło
wyd
Zawsze możesz użyć,
ed
aby dodać linię do istniejącego pliku.Detale
Bity wokół
<!DOCTYPE html>
poleceń są poleceniami, byed
polecił mu dodanie tej linii do plikumy.html
.sed
Wierzę, że tego polecenia
sed
można również użyć:źródło
Możesz także zrobić ręcznie to, co
perl -i
robi pod maską:Jak
perl -i
, nie ma kopii zapasowej, i jak większość rozwiązań podanych tu uwaga może wpływać na uprawnienia własność pliku i może okazać się dowiązania do zwykłego pliku.Z:
sed
nadpisze sam plik, więc nie wpłynie na własność i uprawnienia ani dowiązania symboliczne. Działa z GNU,sed
ponieważsed
zwykle przed odczytaniem bufora pełnego danychfile
(4k w moim przypadku)i
. To nie zadziałałoby, gdyby plik był większy niż 4k, z wyjątkiem tego, żesed
buforuje również jego dane wyjściowe.Zasadniczo
sed
działa na blokach 4k do czytania i pisania. Jeśli linia do wstawienia jest mniejsza niż 4k,sed
nigdy nie zastąpi bloku, którego jeszcze nie przeczytała.Nie liczyłbym na to.
źródło
echo '<!DOCTYPE html>'
lub uciekł bez cudzysłowów.FreeBSD sed , który jest również używany w systemie Mac OS X, potrzebuje
-e
opcji po-i
przełączniku, aby poprawnie zdefiniować i rozpoznać następujące polecenie (wyrażenie regularne) poprawnie i jednoznacznie.Innymi słowy,
sed -i -e ...
powinien działać zarówno z FreeBSD, jak i GNUsed
.Mówiąc bardziej ogólnie, pominięcie rozszerzenia kopii zapasowej po FreeBSD
sed -i
wymaga jakiejś wyraźnejsed
opcji lub przełączenia się,-i
aby uniknąć pomyłek ze strony FreeBSDsed
podczas analizowania argumentów wiersza poleceń.(Należy jednak pamiętać, że
sed
edycje plików w miejscu prowadzą do zmian i-węzłów plików, patrz edycja plików w miejscu ).(Jako ogólna wskazówka, najnowsze wersje FreeBSD
sed
mają-r
przełącznik zwiększający kompatybilność z GNUsed
).źródło
bsdsed -i -e 's/a/A/'
jest edycją lokalną, lecz edycją z zapisaniem oryginału z przyrostkiem „-e” ( ).testfile.txt-e
Aby emulować
sed -i
jeden plik przenośnie, unikając w jak największym stopniu warunków wyścigu:Nawiasem mówiąc, rozwiązuje to również możliwy problem, który
sed -i
wprowadza, w zależności od uprawnień do katalogu i plików,sed -i
może umożliwić użytkownikowi zastąpienie pliku, którego ten użytkownik nie ma uprawnień do edycji.Możesz także wykonywać kopie zapasowe, takie jak:
źródło
Możesz używać Vima w trybie Ex:
1
wybierz pierwszą linięi
wstaw tekst i znak nowej liniix
Zapisz i zamknijLub nawet, jak w komentarzach, zwykły stary standard
ex
:źródło
ex
, z tym wyjątkiem, że implementacje nie są wymagane do obsługi wielu-c
flag. Dla pewnej przenośnościprintf '%s\n' 1i '<!DOCTYPE html>' . x | ex file