додайте текст із відлунням без нового рядка


15

Я хочу додати текст до подібного файлу echo "abc" >>file.txt.

Але це додається abcпісля нового рядка

Як я можу додати abcв кінці файлу ехо без нового рядка?


2
У файлі вже є новий рядок, ви просто додаєте його після нього. Тож вам доведеться замінити символ нового рядка з останнього рядка на "abc".
ctrl-alt-delor

Ласкаво просимо до StackExchange! Ваше питання добре; було б краще, якби ви вказали приклади вмісту вашого файлу (перед додаванням, що ви отримуєте після додавання, що хочете замість цього). Я говорю це тому, що одна з відповідей полягає в тому, як додати abcбез остаточного нового рядка, який (уважно прочитавши ваше запитання), схоже, не є тим, що ви хочете.
Закон29

Відповіді:


19

echo "abc" >>file.txtставить новий рядок після abc , не раніше. Якщо ви закінчилися з abcйого власним рядком, це означає, що новий рядок раніше abcвже був у file.txt.

Зауважте, що цілком нормально, щоб текстовий файл закінчувався в новому рядку. У unix рядок складається з послідовності символів, відмінних від null⁰ або newline, за якими слідує новий рядок. 1 Отже, будь-який не порожній текстовий файл закінчується символом нового рядка.

Якщо ви хочете додати текст до останнього рядка файла, ви не можете це зробити >>, оскільки це завжди додається до файлу, тому він завжди записується після останнього нового рядка. Натомість вам потрібен інструмент, який здатний змінювати існуючий файл. Наприклад, ви можете використовувати sed :

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

У команді sed перший $означає "виконати наступну команду лише в останньому рядку", команда s/REGEX/REPLACEMENT/замінює REGEX на ЗАМОВЛЕННЯ, а регулярний вираз $відповідає в кінці рядка.

Команда sed Linux має вбудовану функцію для автоматизації цієї послідовності створення нового файлу та заміни, тож ви можете скоротити її до

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

Це нульовий байт, який ASCII називає NUL, а Unicode викликає U + 0000. Програми обробки тексту можуть або не можуть впоратися з цим символом.
1 Див. Визначення символів текстового файлу , рядка та нового рядка в розділі "Визначення" розділу " Основні визначення " IEEE 1003.1-2008: 2016.


2
Чи має ваш другий абзац означати, що файл, який не закінчується новим рядком, не є текстовим файлом? Наприклад, якщо я беру існуючий текстовий файл ASCII, який закінчується новим рядком і додаю єдиний байт 0x41(ASCII 'A'), технічно це вже не текстовий файл? Якщо так, я б запропонував наголосити на цьому, оскільки це начебто неінтуїтивне визначення; якщо ні, то невелика зміна формулювання може допомогти уникнути плутанини.
David Z

2
@DavidZ: Це стандартне визначення текстового файлу в Unixland. IIRC десь навіть у POSIX.
Кевін

1
@Kevin Цікаво, я раніше цього не чув. Ну, навіть якщо це стандартно, я думаю, що це щось не інтуїтивно.
David Z

15

Я не думаю, що це можливо за допомогою echoкоманди, sedзамість цього використовуйте наступний підхід:

sed -i '$ s/$/abc/' file.txt
  • -i- змінити файл на місці
  • $ - вказують останній запис / рядок
  • s/$/abc/- замінити кінець рядка $підрядкою abc(для останнього запису)

2
Зауважте, що "на місці" насправді не означає на місці. Це означає "записати відредагований вміст у тимчасовий іменований файл поряд із існуючим файлом та замінити його". Ви можете довести це, подивившись на date >file; ls -i file; sed -i 's/201/ZZZ/' file; ls -i file
індекси

@roaima, мені відомо про зміну номера inode у sed.
RomanPerekhrest

2
Я думав, що ви були б, але я був стурбований тим, що з наголосом на місці ночі ОП думаю, що це може бути використане для уникнення використання подвійного місця на диску, наприклад, з великим файлом.
roaima

@roaima, ніч думай -> може подумати ...
RomanPerekhrest

Що робити, якщо я хочу замінити abc змінною? Використання '$ s/$/$1/'відбитків$1
Флоріан Каштелан

14

Якщо припустити, що файл вже не закінчується в новому рядку, і ви просто хочете додати ще якийсь текст, не додаючи жодного, ви можете використовувати -nаргумент, наприклад

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

Однак деякі системи UNIX не пропонують такий варіант; якщо це ви можете використовувати printf, наприклад,

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

(початковий %sаргумент - захист від додаткового тексту, що містить %у ньому символи форматування)

Від man echo(на macOS Висока Сьєрра):

Не друкуйте символ нового рядка. Це також може бути досягнуто шляхом додавання '\c'до кінця рядка, як це робиться системами, сумісними з iBCS2. Зауважимо, що цей параметр, а також ефект від '\c'них визначені реалізацією в IEEE Std 1003.1-2001 ("POSIX.1") із змінами, внесеними Кор. 1-2002. Програми, спрямовані на максимальну портативність, наполегливо рекомендується використовувати printf(1)для придушення символу нового рядка.


Це, очевидно , закінчується новим рядком. echo -nне ставив би нову лінію в кінці abc, але abcвсе одно передує нова лінія, чого користувач хоче уникнути.
Кусалаланда

@Kusalananda Моя відповідь скоріше використовувала припущення, що ОП намагатиметься змінити їхній процес таким чином, щоб неправдиві \nвиявилися в першу чергу. Більше варіантів краще, особливо якщо вони не передбачають необхідності переписувати весь файл щоразу, коли відбудеться зміна (що може отримати досить повільний і запуститись у поліном час, якщо це робиться повторно).
пухнастий

9

Якщо у вас є truncateкоманда, а у вашому текстовому файлі є останній символ, ви можете його видалити, а потім додати текст так:

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

(Зауважте, що truncateнічого не цікавить вміст файлу, і в цьому прикладі просто зменшується розмір файлу на один байт. Якщо ваш останній символ не є одиничним байтом, тобто є багатобайтовим "широким" символом, ви введете корупцію.)


5

Що ви хочете, це додати його в кінці останнього рядка, так що безпосередньо перед роздільником цього останнього рядка, так що безпосередньо перед останнім символом файлу.

З ksh93, ви можете:

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

Де 1<>стандартний оператор для відкриття файлу в режимі читання + запису (а ще важливіше без укорочення ) на stdout і >#((...))є оператором, що шукає ksh93 (тут потрібно шукати до останнього байта). Зауважте, що echoпише, abc<newline>де aперезаписується новий рядок, який там був, і echoдодається власний новий рядок.

zshеквівалент:

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

Хоча для більш точного еквівалента, вам також потрібно буде надрукувати повідомлення про помилку, якщо не вдалося шукати:

zmodload zsh/system
if sysseek -w end -u 1 -1; then
  echo abc
else
  syserror -p "$0: $LINENO: seek: "
fi 1<> file

-1

Можливо, UUOC, але ви також можете зробити:

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

Як зазначає Жилл, ця команда обмежена:

Це здебільшого працює, але не, якщо іноді в кінці файлу є порожній рядок та порожній рядок безпосередньо перед цим. Наприклад, файл із фіксованою кількістю рядків, де останній рядок спочатку порожній і продовжується з часом, а наступний рядок може бути іноді порожнім.

Крім того, будьте обережні при використанні catфайлів, з якими ви не знайомі:

Висновок :

Використовуйте sed


2
Це здебільшого працює, але не, якщо іноді в кінці файлу є порожній рядок та порожній рядок безпосередньо перед цим. Наприклад, файл із фіксованою кількістю рядків, де останній рядок спочатку порожній і продовжується з часом, а наступний рядок може бути іноді порожнім.
Жил "ТАК - перестань бути злим"

Чи слід його видалити? Я точно думаю, що Роман / ваша відповідь - це правильний шлях, але я знаю, що мені особисто подобається бачити альтернативи, і ОП попросив echo: p
jesse_b

1
Також це ставить весь файл у командному рядку
n.caillou

@ n.caillou так? Це не надрукує нічого для STDOUT.
jesse_b

2
Ну, жодна з цих вразливих ситуацій насправді не пов'язана cat, але з проблемами з довільними послідовностями виходу, що надсилаються до терміналу.
ilkkachu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.