dołącz tekst z echem bez nowej linii

15

Chcę dołączyć tekst do pliku jak echo "abc" >>file.txt.

Ale to dodaje abcpo nowej linii

Jak mogę dodać abcna końcu pliku echo bez nowej linii?

choijj
źródło
2
Plik ma już nową linię, którą dopiero dodajesz. Będziesz musiał zastąpić znak nowej linii z ostatniego wiersza „abc”.
ctrl-alt-delor
Witamy w StackExchange! Twoje pytanie jest dobre; byłoby lepiej, gdybyś podał przykłady zawartości pliku (przed dodaniem, co otrzymujesz po dodaniu, co chciałeś zamiast tego). Mówię to, ponieważ jedną z odpowiedzi jest to, jak dodać abcbez ostatniego nowego wiersza, który (po uważnym przeczytaniu pytania) nie wydaje się tym, czego chcesz.
Law29

Odpowiedzi:

19

echo "abc" >>file.txtwstawia nowy wiersz po abc , a nie przed. Jeśli skończysz z abcwłasną linią, oznacza to, że nowa linia wcześniej abcbyła już w file.txt.

Zauważ, że całkowicie normalne jest, aby plik tekstowy kończył się nową linią. W systemie uniksowym linia składa się z sekwencji znaków innych niż null⁰ lub nowa linia, po której następuje nowa linia. 1 Dlatego każdy niepusty plik tekstowy kończy się znakiem nowej linii.

Jeśli chcesz dodać tekst do ostatniego wiersza pliku, nie możesz tego zrobić >>, ponieważ to zawsze dołącza się do pliku, więc zawsze pisze po ostatniej nowej linii. Zamiast tego potrzebujesz narzędzia, które może modyfikować istniejący plik. Na przykład możesz użyć sed :

sed '$ s/$/abc/' file.txt >file.txt.new && mv file.txt.new file.txt

W poleceniu sed pierwsze $oznacza „wykonaj następujące polecenie tylko w ostatnim wierszu”, polecenie s/REGEX/REPLACEMENT/zastępuje REGEX przez WYMIANA, a wyrażenie regularne $pasuje na końcu wiersza.

Polecenie sed systemu Linux ma wbudowaną funkcję automatyzującą tę sekwencję tworzenia-nowego-pliku-i-zamiany, dzięki czemu można ją skrócić

sed -i '$ s/$/abc/' file.txt

To bajt zerowy, który ASCII nazywa NUL, a Unicode nazywa U + 0000. Programy przetwarzające tekst mogą, ale nie muszą, radzić sobie z tym znakiem.
1 Patrz definicje pliku tekstowego , wiersza i znaku nowej linii w sekcji „Definicje” rozdziału Definicje podstawowe w IEEE 1003.1-2008: 2016.

Gilles „SO- przestań być zły”
źródło
2
Czy twój drugi akapit ma sugerować, że plik, który nie kończy się na nowej linii, nie jest plikiem tekstowym? Np. Jeśli wezmę istniejący plik tekstowy ASCII, który kończy się nową linią i dołączę pojedynczy bajt 0x41(ASCII 'A'), to technicznie nie jest to już plik tekstowy? Jeśli tak, sugeruję podkreślenie tego punktu, ponieważ jest to rodzaj nieintuicyjnej definicji; jeśli nie, niewielka zmiana w sformułowaniu może pomóc uniknąć nieporozumień.
David Z
2
@DavidZ: To jest standardowa definicja pliku tekstowego w Unixland. IIRC jest nawet gdzieś w POSIX.
Kevin,
1
@Kevin Interesujące, nigdy wcześniej tego nie słyszałem. Cóż, nawet jeśli jest to standard, myślę, że jest to trochę nieintuicyjne.
David Z
15

Nie wydaje mi się, aby było to możliwe za pomocą echopolecenia, sedzamiast tego użyj następującego podejścia:

sed -i '$ s/$/abc/' file.txt
  • -i- zmodyfikować plik inplace
  • $ - wskazać ostatni rekord / linię
  • s/$/abc/- zamień koniec linii na $podłańcuch abc(dla ostatniego rekordu)
Roman Perekhrest
źródło
2
Pamiętaj, że „na miejscu” tak naprawdę nie oznacza na miejscu. Oznacza to „zapisz edytowaną treść do tymczasowego pliku o nazwie obok istniejącego pliku, a następnie zastąp go”. Możesz to udowodnić, patrząc na idate >file; ls -i file; sed -i 's/201/ZZZ/' file; ls -i file
węzły za
@roaima, wiem o zmianie numeru i-węzła przez sed.
RomanPerekhrest
2
Myślałem, że tak, ale martwiłem się, że z naciskiem na wstawienie nocy OP myślę, że można by tego użyć, aby uniknąć podwójnego wykorzystania miejsca na dysku, np. Z dużym plikiem.
roaima,
@roaima, noc myśli -> może myśleć ...
RomanPerekhrest
Co jeśli chcę zastąpić abc zmienną? Korzystanie z '$ s/$/$1/'odcisków$1
Florian Castelain
14

Zakładając, że plik nie kończy się na nowej linii i po prostu chcesz dodać trochę tekstu bez dodawania jednego, możesz użyć -nargumentu, np.

echo -n "some text here" >> file.txt

Jednak niektóre systemy UNIX nie zapewniają tej opcji; w takim przypadku możesz użyć printfnp

printf %s "some text here" >> file.txt

(początkowym %sargumentem jest ochrona przed dodatkowym tekstem zawierającym %znaki formatujące)

Z man echo(na macOS High Sierra):

-n

Nie drukuj końcowego znaku nowej linii. Można to również osiągnąć poprzez dołączenie '\c'na końcu łańcucha, tak jak dzieje się to w systemach kompatybilnych z iBCS2. Należy zauważyć, że ta opcja, jak również wpływ '\c'są zdefiniowane w implementacji w IEEE Std 1003.1-2001 („POSIX.1”), zmienionej przez Cor. 1-2002. Zachęcamy do korzystania printf(1)z aplikacji mających na celu maksymalną przenośność do tłumienia znaku nowej linii.

puszysty
źródło
To dość oczywisty nie kończy się nową linią. echo -nnie wstawi nowego wiersza na końcu abc, ale abcnadal będzie poprzedzony nowym wierszem, którego użytkownik chce uniknąć.
Kusalananda
@Kusalananda Moja odpowiedź była bardziej oparta na założeniu, że OP będzie próbował zmienić swój proces tak, aby fałszywy \nnie pojawił się w pierwszej kolejności. Więcej opcji jest lepszych, szczególnie gdy nie wymagają przepisania całego pliku za każdym razem, gdy nastąpi zmiana (która może być dość wolna i działać w czasie wielomianowym, jeśli jest to powtarzane).
puszysty
9

Jeśli masz truncatepolecenie, a plik tekstowy ma NL jako ostatni znak, możesz go usunąć, a następnie dołączyć tekst w następujący sposób:

truncate --size -1 file.txt
echo "abc" >>file.txt

(Zauważ, że truncatenic nie obchodzi zawartości pliku, aw tym przykładzie po prostu zmniejsza rozmiar pliku o jeden bajt. Jeśli twój ostatni znak nie jest jednym bajtem, tj. Jest to wielobajtowy „szeroki” znak, wówczas wprowadzisz uszkodzenie).

roaima
źródło
5

To, co chcesz, to dodać go na końcu ostatniego wiersza, a więc tuż przed ogranicznikiem tego ostatniego wiersza, a więc tuż przed ostatnim znakiem pliku.

Za pomocą ksh93możesz:

echo abc 1<> file >#((EOF - 1))

Gdzie 1<>standardowy operator otwiera plik w trybie do odczytu i zapisu (a co ważniejsze bez obcięcia ) na standardowym wyjściu i >#((...))jest operatorem szukającym specyficznym dla ksh93 (tutaj, aby szukać przed ostatnim bajtem). Zauważ, że echozapisuje abc<newline>tam, gdzie anadpisuje nową linię, która tam była i echododaje własną nową linię .

zshRównoważne:

zmodload zsh/system
{sysseek -w end -u 1 -1 && echo abc} 1<> file

Chociaż dla dokładniejszego odpowiednika, będziesz musiał wydrukować komunikat o błędzie, jeśli nie będziesz szukać:

zmodload zsh/system
if sysseek -w end -u 1 -1; then
  echo abc
else
  syserror -p "$0: $LINENO: seek: "
fi 1<> file
Stéphane Chazelas
źródło
-1

Prawdopodobnie numer UUOC, ale możesz również wykonać:

echo "$(cat file.txt)abc" >file.txt

Jak podkreśla Gilles, to polecenie jest ograniczone:

Działa to głównie, ale nie wtedy, gdy na końcu pliku znajduje się pusta linia i bezpośrednio przed nią pusta linia. Np. Plik ze stałą liczbą linii, w którym ostatnia linia jest początkowo pusta i jest rozszerzana w czasie, a linia od ostatniej do ostatniej może czasami być pusta.

Ponadto należy zachować ostrożność podczas korzystania catz plików, których nie znasz:

Wniosek :

Użyj sed

jesse_b
źródło
2
Działa to głównie, ale nie wtedy, gdy na końcu pliku znajduje się pusta linia i bezpośrednio przed nią pusta linia. Np. Plik ze stałą liczbą linii, w którym ostatnia linia jest początkowo pusta i jest rozszerzana w czasie, a linia od ostatniej do ostatniej może czasami być pusta.
Gilles „SO- przestań być zły”
Czy powinienem to usunąć? Zdecydowanie uważam, że Roman / Twoja odpowiedź jest właściwą drogą, ale wiem, że osobiście lubię widzieć alternatywy, a OP poprosił o echo: p
jesse_b
1
Także to powoduje umieszczenie całego pliku w wierszu poleceń
n.caillou,
@ n.caillou huh? To nie wydrukuje niczego do STDOUT.
jesse_b
2
Żadna z tych luk nie jest tak naprawdę związana cat, ale z problemami z wysyłaniem dowolnych sekwencji ucieczki do terminala.
ilkkachu