sed на OSX вставити в певному рядку


24

Тому я деякий час використовував "sed" на Linux, але у мене виникли деякі труднощі при спробі використовувати його на OSX, оскільки "POSIX sed" і "GNU sed" мають дуже мало відмінностей. В даний час я борюся з тим, як вставити рядок тексту після певного номера рядка. (у цьому випадку рядок 4)

У Linux я би зробив щось подібне:

sed --in-place "4 a\  mode '0755'" file.txt

Отже, на OSX я спробував це:

sed -i "" "4 a\ mode '0755'" file.txt

Однак це надає мені помилки "зайві символи після \ в кінці команди". Будь-які ідеї, що тут не так? У мене є друкарська помилка? Або я не розумію ще однієї різниці між версіями sed?


2
Можна підтвердити, що це не працює на MacOS 10.6.8. Відмінно працює на debian 6.0.3.
тинк

Відповіді:


24

Власне кажучи, специфікація POSIXsed вимагає нового рядка після a\:

[1addr]a\
text

Введіть текст на стандартний вихід, як описано раніше.

Це робить написання дотепів трохи болю, яка, ймовірно , є причиною для подальшого розширення GNU до a, iі cкоманди:

Як розширення GNU, якщо між aта новим рядком є ​​інша \послідовність пробілів , то текст цього рядка, починаючи з першого символу без пробілу після a, приймається як перший рядок текстового блоку. (Це дозволяє спростити сценарій додавання одно рядків.) Це розширення також працює з командами iта c.

Таким чином, щоб бути переносним зі своїм sedсинтаксисом, вам потрібно буде a\якось включити новий рядок . Найпростіший спосіб - просто вставити цитований новий рядок:

$ sed -e 'a\
> text'

(де $і >є підказки оболонки). Якщо ви виявите, що біль bash[1] має $' 'синтаксис цитування для вставки вхідних стилів С, тому просто використовуйте

sed -e 'a\'$'\n''text'

[1] і mksh (r39b +) та деякі не-баш-бурнові оболонки (наприклад, / bin / sh у FreeBSD 9+)


Дуже інформативна відповідь. Дякуємо за підказку щодо синтаксису цитування башів.
cjackson

14

Як описано у цій відповіді , це корисно при використанні команд sed, як iі aу використанні декількох -e "..."пропозицій. Кожна з цих статей буде розумітися розділеною новими рядками. Команди iі та aважко використовувати у вбудованих сценаріях sed в іншому випадку (вони розроблені для використання у мультилінійному файлі скриптів sed, на який посилаються за допомогою sed -f file ...). Схоже, ви не можете використовувати неявний новий рядок, введений в кінці -eпункту, щоб відокремити текст a\і рядок тексту, який потрібно додати. Але ви можете використовувати його для завершення рядка тексту, який слід додати.

У цьому конкретному випадку те, що ви намагаєтесь зробити, насправді може бути виконане за допомогою одного -e ...пункту. Ви просто повинні правильно використовувати aкоманду. За стандартом POSIX aповинен дотримуватися a \, після цього повинен бути новий рядок, тоді решта наступного рядка буде вставлена ​​(доки не з’явиться новий рядок або кінець -eпункту). Отже, ви можете зробити:

sed -i "" -e $'4 a\\\n'"mode '0755'" file.txt

2
Якщо ви хочете розібратися, на які функції ви покладаєтесь, - це Gnu-isms, ця сторінка може допомогти: wiki.alpinelinux.org/wiki/Regex . Хоча це обмежується лише функціями регулярного вираження; не інші команди sed.
сумнівним

5

Здається, GNU sed набагато частіше використовується, ніж POSIX sed, спираючись на приклади / підручники, якими я користувався в будь-якому випадку.

Я виявив, що набагато простіше просто встановити GNU sed на будь-яку машину OSX, яку я використовую. Якщо ви зацікавлені, найкращий спосіб зробити це - встановити його через Homebrew .

Ви можете просто $ brew install gnu-sedотримати або отримати всі загальні утиліти GNU $ brew install coreutils.

Тоді, коли ви зіткнетеся з проблемою синтаксису з dateбудь-якою іншою програмою, ви можете просто скористатися версією GNU. Врешті-решт я просто вирішив, що легше завжди використовувати версії GNU і ставити їх раніше, ніж системні версії в моїй PATH.


5

Perl не страждає від такої залежної від платформи GNU порівняно з не GNU проти "фірмових" ідіосинкрасій. Ви можете зробити:

perl -ni.old -e 'print;if ($.==4) {print "mode 0755\n"}' file

-n' option creates a loop that reads every line of the input file. Unlike its cousin-P (not used here) it doesn't automatically print every line read. The-i invokes in-place replacement. The argument to-i (viz. ".old") can be dropped or changed. It leaves a backup of the unmodified file. The -eсигналізує про початок сценарію.

$.Позначає лінію-номер, починаючи з лінії-1. Таким чином, командний рядок читає "файл", і коли номер рядка дорівнює 4, він друкує цей рядок, а потім все, що ви хочете ввести.

Я б не поспішав додати, що Perl зобов'язаний своїм корінням sedAWK та C, тому синтаксис простих підстановок тощо не є дуже крутою кривою навчання.


Гарна відповідь! Але ви можете трохи спростити це. Спробуйте це: perl -wlpi.old -e 'print "mode 0755" if $. == 5' file.txt. Тут -pдобре працює перемикач (оскільки ми хочемо надрукувати кожен рядок); нам просто потрібно змінити логіку з "друк після рядка 4" на "друк перед рядком 5". І -lперемикач робить так, що "\ n" друкується автоматично з кожним print, тому вам не доведеться друкувати його самостійно.
JL
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.