To prawdopodobnie skomplikowane rozwiązanie .
Szukam prostego operatora, takiego jak „>>”, ale do poprzedzania.
Obawiam się, że nie istnieje. Muszę zrobić coś takiego
mv myfile tmp cat myheader tmp> myfile
Coś mądrzejszego?
To prawdopodobnie skomplikowane rozwiązanie .
Szukam prostego operatora, takiego jak „>>”, ale do poprzedzania.
Obawiam się, że nie istnieje. Muszę zrobić coś takiego
mv myfile tmp cat myheader tmp> myfile
Coś mądrzejszego?
mktemp
? Zawsze możesz później wyczyścić plik tymczasowy ...Odpowiedzi:
Poniższy hack był szybką, spontaniczną odpowiedzią, która zadziałała i otrzymała wiele pozytywnych głosów. Potem, gdy pytanie stawało się coraz bardziej popularne i mijało więcej czasu, oburzeni ludzie zaczęli zgłaszać, że to trochę działa, ale mogą się zdarzyć dziwne rzeczy, albo po prostu nie działa, więc przez jakiś czas było wściekle odrzucane. Taka zabawa.
Rozwiązanie wykorzystuje dokładną implementację deskryptorów plików w twoim systemie, a ponieważ implementacja różni się znacznie między nixami, jego sukces jest całkowicie zależny od systemu, definitywnie nieprzenośny i nie należy na nim polegać w przypadku niczego nawet mało ważnego.
Teraz, gdy to wszystko zniknęło, odpowiedź brzmiała:
Stworzenie innego deskryptora pliku dla pliku file (
exec 3<> yourfile
), a następnie zapisywanie do this (>&3
) wydaje się przezwyciężyć dylemat odczytu / zapisu tego samego pliku. U mnie działa na plikach 600K z awk. Jednak próba tej samej sztuczki przy użyciu „kota” kończy się niepowodzeniem.Przekazanie przedrostka jako zmiennej do awk (
-v TEXT="$text"
) rozwiązuje problem dosłownych cudzysłowów, który uniemożliwia wykonanie tej sztuczki z 'sed'.#!/bin/bash text="Hello world What's up?" exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3
źródło
To nadal używa pliku tymczasowego, ale przynajmniej jest w jednym wierszu:
echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile
Kredyt: BASH: Dołącz tekst / wiersze do pliku
źródło
-
późniejcat
?echo -n "text"
yourfile
jest dowiązaniem symbolicznym, to nie zrobi tego, co chcesz.echo '0a your text here . w' | ed some_file
ed jest edytorem standardów! http://www.gnu.org/fun/jokes/ed.msg.html
źródło
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee: Twoja metoda nie ma gwarancji, że zadziała i prawdopodobnie zawiedzie, jeśli dodasz więcej niż 4096 bajtów rzeczy (przynajmniej tak się dzieje z gnu awk, ale przypuszczam, że inne implementacje będą miały podobne ograniczenia). W takim przypadku nie tylko zakończy się niepowodzeniem, ale wejdzie w nieskończoną pętlę, w której odczyta własne wyjście, dzięki czemu plik będzie rósł, dopóki cała dostępna przestrzeń nie zostanie wypełniona.
Wypróbuj sam:
exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3
(ostrzeżenie: zabij go po chwili lub zapełni system plików)
Co więcej, edytowanie plików w ten sposób jest bardzo niebezpieczne i jest to bardzo zła rada, ponieważ jeśli coś się stanie podczas edycji pliku (awaria, pełny dysk), prawie na pewno pozostaniesz z plikiem w niespójnym stanie.
źródło
Niemożliwe bez pliku tymczasowego, ale oto oneliner
{ echo foo; cat oldfile; } > newfile && mv newfile oldfile
Możesz użyć innych narzędzi, takich jak ed lub perl, aby zrobić to bez plików tymczasowych.
źródło
Warto zauważyć, że często dobrym pomysłem jest bezpieczne wygenerowanie pliku tymczasowego za pomocą narzędzia takiego jak mktemp , przynajmniej jeśli skrypt zostanie kiedykolwiek wykonany z uprawnieniami roota. Możesz na przykład wykonać następujące czynności (ponownie w bash):
(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )
źródło
Jeśli potrzebujesz tego na kontrolowanych komputerach, zainstaluj pakiet "moreutils" i użyj "sponge". Następnie możesz:
źródło
{ echo "prepended text"; cat myfile } | sponge myfile
Używając bash heredoc można uniknąć konieczności posiadania pliku tmp:
cat <<-EOF > myfile $(echo this is prepended) $(cat myfile) EOF
To działa, ponieważ $ (cat myfile) jest sprawdzane podczas sprawdzania skryptu bash, przed wykonaniem cat z przekierowaniem.
źródło
zakładając, że plik, który chcesz edytować, to my.txt
$cat my.txt this is the regular file
Plik, który chcesz dodać na początku, to nagłówek
Upewnij się, że w pliku nagłówkowym znajduje się ostatnia pusta linia.
Teraz możesz go poprzedzić
$cat header <(cat my.txt) > my.txt
Skończysz z
O ile wiem, działa to tylko w „bash”.
źródło
this is the header
w moim.txt. Nawet po zaktualizowaniu Bash4.3.42(1)-release
, otrzymuję ten sam wynik.<(...)
) , więc nie ma gwarancji, żemy.txt
zostanie odczytany w całości z góry , bez czego ta technika nie zadziała.Kiedy zaczynasz robić rzeczy, które stają się trudne w skrypcie powłoki, stanowczo sugerowałbym sprawdzenie przepisania skryptu w „odpowiednim” języku skryptowym (Python / Perl / Ruby / itp.)
Jeśli chodzi o dołączanie wiersza z wyprzedzeniem do pliku, nie można tego zrobić za pomocą pipingu, ponieważ gdy robisz coś podobnego
cat blah.txt | grep something > blah.txt
, nieumyślnie pusta plik. Istnieje małe polecenie narzędzia o nazwie,sponge
które możesz zainstalować (robisz tocat blah.txt | grep something | sponge blah.txt
i buforuje zawartość pliku, a następnie zapisuje ją do pliku). Jest podobny do pliku tymczasowego, ale nie musisz tego robić jawnie. ale powiedziałbym, że to „gorszy” wymóg niż, powiedzmy, Perl.Może istnieć sposób na zrobienie tego przez awk lub podobny, ale jeśli musisz użyć skryptu powłoki, myślę, że plik tymczasowy jest zdecydowanie najłatwiejszym (/ jedynym?) Sposobem.
źródło
Jak sugeruje Daniel Velkov, użyj koszulki.
Dla mnie to proste, inteligentne rozwiązanie:
{ echo foo; cat bar; } | tee bar > /dev/null
źródło
EDYCJA: To jest zepsute. Zobacz Dziwne zachowanie podczas poprzedzania pliku z kotem i tee
Obejście problemu z nadpisaniem polega na użyciu
tee
:źródło
Ten, którego używam. Ten pozwala określić kolejność, dodatkowe znaki itp. W taki sposób, w jaki lubisz:
echo -e "TEXTFIRSt\n$(< header)\n$(< my.txt)" > my.txt
PS: tylko nie działa, jeśli pliki zawierają tekst z odwrotnym ukośnikiem, ponieważ jest interpretowany jako znaki ucieczki
źródło
Głównie dla zabawy / shell golfa, ale
ex -c '0r myheader|x' myfile
załatwi sprawę i nie ma żadnych potoków ani przekierowań. Oczywiście, vi / ex nie jest tak naprawdę do użytku nieinteraktywnego, więc vi na chwilę się wyświetli.
źródło
Dlaczego po prostu nie użyć polecenia ed (jak już sugeruje tu fluffle)?
ed czyta cały plik do pamięci i automatycznie przeprowadza edycję pliku w miejscu!
Więc jeśli twój plik nie jest tak duży ...
# cf. "Editing files with the ed text editor from scripts.", # http://wiki.bash-hackers.org/doku.php?id=howto:edit-ed prepend() { printf '%s\n' H 1i "${1}" . wq | ed -s "${2}" } echo 'Hello, world!' > myfile prepend 'line to prepend' myfile
Jeszcze innym obejściem byłoby użycie otwartych uchwytów plików, zgodnie z sugestią Jürgena Hötzela w Przekieruj dane wyjściowe z seda 's / c / d /' myFile do myFile
echo cat > manipulate.txt exec 3<manipulate.txt # Prevent open file from being truncated: rm manipulate.txt sed 's/cat/dog/' <&3 > manipulate.txt
Wszystko to można oczywiście umieścić w jednej linii.
źródło
Wariant rozwiązania cb0 z „brakiem pliku tymczasowego” w celu dodania stałego tekstu na początku:
echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified )
Znowu polega to na wykonaniu podpowłoki - (..) - aby uniknąć odmowy cat odmowy posiadania tego samego pliku na wejściu i wyjściu.
Uwaga: podobało mi się to rozwiązanie. Jednak na moim komputerze Mac oryginalny plik został utracony (sądziłem, że nie powinien, ale tak się dzieje). Można to naprawić, pisząc rozwiązanie jako: echo "tekst na początek" | cat - file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified
źródło
Oto, co odkryłem:
echo -e "header \n$(cat file)" >file
źródło
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile
źródło
OSTRZEŻENIE: wymaga to nieco więcej pracy, aby spełnić potrzeby PO.
Powinien istnieć sposób, aby podejście seda @shixilun działało pomimo jego obaw. Musi istnieć polecenie bash, aby uniknąć białych spacji podczas wczytywania pliku do ciągu zastępującego sed (np. Zamień znaki nowej linii na '\ n'. Polecenia powłoki
vis
icat
mogą obsługiwać znaki niedrukowalne, ale nie białe spacje, więc to nie rozwiąże operacji problem:sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt
kończy się niepowodzeniem ze względu na nieprzetworzone znaki nowej linii w skrypcie zastępczym, które należy poprzedzić znakiem kontynuacji linii () i być może poprzedzonym znakiem &, aby zachować powłokę i seda w dobrym stanie, jak ta odpowiedź SO
sed
ma ograniczenie rozmiaru do 40 KB dla nieglobalnych poleceń wyszukiwania i zamiany (bez końcowego / g po wzorcu), więc prawdopodobnie pozwoliłoby uniknąć przerażających problemów z przepełnieniem bufora w awk, przed którymi ostrzegał anonimowy.źródło
sed -i -e "1s/^/new first line\n/" old_file.txt
źródło
Za pomocą $ (polecenie) możesz zapisać wynik polecenia do zmiennej. Więc zrobiłem to w trzech poleceniach w jednej linii i bez pliku tymczasowego.
originalContent=$(cat targetfile) && echo "text to prepend" > targetfile && echo "$originalContent" >> targetfile
źródło
Jeśli piszesz w BASH, możesz po prostu wydać:
To jest właściwie w złożonym przykładzie, który sam zadałeś w swoim własnym pytaniu.
źródło
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
, ale to wystarczająco różni się od mojej odpowiedzi, że powinna to być jego własna odpowiedź.Jeśli masz duży plik (w moim przypadku kilkaset kilobajtów) i masz dostęp do Pythona, jest to znacznie szybsze niż
cat
rozwiązania potokowe:python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'
źródło
Rozwiązanie z
printf
:new_line='the line you want to add' target_file='/file you/want to/write to' printf "%s\n$(cat ${target_file})" "${new_line}" > "${target_file}"
Możesz też:
printf "${new_line}\n$(cat ${target_file})" > "${target_file}"
Ale w takim przypadku musisz być pewien, że
%
nigdzie nie ma , w tym zawartości pliku docelowego, ponieważ można to zinterpretować i zepsuć wyniki.źródło
echo
wydaje się bezpieczniejszą opcją.echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
pliku docelowym, a nie o pliku docelowymMożesz użyć wiersza poleceń perla:
perl -i -0777 -pe 's/^/my_header/' tmp
Gdzie -i utworzy bezpośrednią zamianę pliku, a -0777 siorbi cały plik i dopasuje ^ tylko początek. -pe wypisze wszystkie linie
Lub jeśli my_header jest plikiem:
perl -i -0777 -pe 's/^/`cat my_header`/e' tmp
Gdzie / e pozwoli na ocenę kodu w zamianie.
źródło
current=`cat my_file` && echo 'my_string' > my_file && echo $current >> my_file
gdzie „my_file” to plik, do którego należy dołączyć „my_string”.
źródło
Najbardziej podoba mi się podejście ed @ fluffle . W końcu przełączniki wiersza poleceń dowolnego narzędzia a polecenia edytora skryptowego są tutaj zasadniczo takie same; nie widząc „czystości” rozwiązania edytora skryptów jako mniejszego lub czegoś innego.
Oto moja jedna linijka dołączona do
.git/hooks/prepare-commit-msg
pliku w repozytorium w.gitmessage
celu zatwierdzenia wiadomości:echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"
Przykład
.gitmessage
:# Commit message formatting samples: # runlevels: boot +consolekit -zfs-fuse #
Robię
1r
zamiast tego0r
, ponieważ pozostawi to pustą linię gotową do zapisu na górze pliku z oryginalnego szablonu. Nie umieszczaj pustej linii na swoim.gitmessage
, skończysz z dwoma pustymi liniami.-s
blokuje wyświetlanie informacji diagnostycznych przez ed.W związku z przechodzeniem przez to odkryłem, że dla vim-buffów dobrze jest mieć również:
[core] editor = vim -c ':normal gg'
źródło
zmienne, ftw?
NEWFILE=$(echo deb http://mirror.csesoc.unsw.edu.au/ubuntu/ $(lsb_release -cs) main universe restricted multiverse && cat /etc/apt/sources.list) echo "$NEWFILE" | sudo tee /etc/apt/sources.list
źródło
Myślę, że to najczystsza odmiana ed:
cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile
jako funkcja:
function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed $1; } cat myheader | prepend myfile
źródło
IMHO nie ma rozwiązania powłoki (i nigdy nie będzie), które działałoby konsekwentnie i niezawodnie niezależnie od rozmiarów dwóch plików
myheader
imyfile
. Powodem jest to, że jeśli chcesz to zrobić bez powracania do pliku tymczasowego (i bez pozwalania powłoce na ciche powtarzanie się do pliku tymczasowego, np. Przez konstrukcje takie jakexec 3<>myfile
, rurociąg dotee
itp."Prawdziwe" rozwiązanie, którego szukasz, musi majstrować przy systemie plików, więc nie jest dostępne w przestrzeni użytkownika i byłoby zależne od platformy: prosisz o zmodyfikowanie wskaźnika systemu plików używanego przez
myfile
do bieżącej wartości wskaźnika systemu plików formyheader
i zamień w systemie plikówEOF
ofmyheader
połączonym odnośnikiem do bieżącego adresu systemu plików wskazywanego przezmyfile
. Nie jest to trywialne i oczywiście nie może tego zrobić użytkownik niebędący superużytkownikiem, a prawdopodobnie też superużytkownik ... Graj z i-węzłami itp.Możesz to mniej więcej udawać, używając urządzeń pętlowych. Zobacz na przykład ten wątek SO .
źródło