sed su OSX si inserisce in una determinata riga


24

Quindi sto usando 'sed' su Linux da un po ', ma ho avuto un po' di difficoltà nel provare ad usarlo su OSX poiché 'POSIX sed' e 'GNU sed' hanno così tante piccole differenze. Attualmente sto lottando su come inserire una riga di testo dopo un certo numero di riga. (in questo caso, riga 4)

Su Linux farei una cosa del genere:

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

Quindi su OSX ho provato questo:

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

Tuttavia, questo continua a darmi un errore "caratteri extra dopo \ alla fine di un comando". Qualche idea di cosa c'è che non va qui? Ho un refuso? O non capisco un'altra differenza tra le versioni di sed?


2
Posso confermare che non funziona su MacOS 10.6.8. Funziona bene su debian 6.0.3.
tink

Risposte:


24

A rigor di termini, la specifica POSIX persed richiede una nuova riga dopo a\:

[1addr]a\
text

Scrivi il testo sullo standard output come descritto in precedenza.

Questo rende la scrittura battute un po 'di dolore, che è probabilmente la ragione per la seguente estensione GNU alla a, ie ccomandi:

Come estensione GNU, se tra la ae la nuova riga esiste un'altra \sequenza di spazi bianchi , il testo di questa riga, che inizia con il primo carattere non di spazi bianchi dopo il a, viene preso come prima riga del blocco di testo . (Ciò consente una semplificazione nello scripting di un'aggiunta di una riga.) Questa estensione funziona anche con i comandi ie c.

Quindi, per essere portatile con la tua sedsintassi, dovrai includere una nuova riga dopo in a\qualche modo. Il modo più semplice è inserire una nuova riga tra virgolette:

$ sed -e 'a\
> text'

(dove $e >sono i prompt della shell). Se trovi che un dolore, bash[1] ha la $' 'sintassi di citazione per l'inserimento di escape in stile C, quindi usa solo

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

[1] e mksh (r39b +) e alcuni shell bourne non bash (es. / Bin / sh in FreeBSD 9+)


Risposta molto istruttiva. Grazie per il suggerimento sulla sintassi di citazione bash.
Jackson il

14

Come descritto in questa risposta , è utile quando si utilizzano comandi sed like ie si ausano più -e "..."clausole. Ciascuna di queste clausole sarà compresa come separata da una nuova riga. I comandi ie asono difficili da usare negli script sed inline altrimenti (sono progettati per l'uso in un file di script sed multilinea invocato utilizzando sed -f file ...). Sembra che non sia possibile utilizzare la nuova riga implicita introdotta dalla fine di una -eclausola per separare a\la riga di testo da aggiungere. Ma puoi usarlo per terminare la riga di testo da aggiungere.

In questo caso specifico, ciò che stai cercando di fare potrebbe in effetti essere realizzato con una singola -e ...clausola. Devi solo usare il acomando correttamente. Secondo lo standard POSIX, adeve essere seguito da un \, quindi deve essere seguito da una nuova riga, quindi verrà inserito il resto della riga successiva (fino a quando -enon viene rilevata una nuova riga o la fine della clausola). Quindi potresti fare:

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

2
Se vuoi ordinare quali sono le funzioni su cui fai affidamento sono i Gnu-ismi, questa pagina può aiutarti: wiki.alpinelinux.org/wiki/Regex . È limitato solo alle funzionalità regex; non gli altri comandi sed.
dubiousjim,

5

GNU sed sembra essere molto più comunemente usato di POSIX sed, sulla base di esempi / tutorial che ho usato comunque.

Ho scoperto che è molto più semplice installare GNU sed su qualsiasi macchina OSX che uso. Se sei interessato, il modo migliore per farlo è installarlo tramite Homebrew .

Puoi semplicemente $ brew install gnu-sedo ottenere tutte le comuni utility GNU con $ brew install coreutils.

Quindi, quando si verifica un problema di sintassi con dateo qualche altro programma, è possibile utilizzare la versione GNU. Alla fine ho appena deciso che era più facile usare sempre le versioni GNU e metterle prima delle versioni di sistema nel mio PATH.


5

Perl non soffre di tali idiosincrasie GNU dipendenti dalla piattaforma rispetto a non GNU vs "proprietarie". Potresti fare:

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

Il -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 -esegna l'inizio dello script.

Il $.simbolo indica il numero di riga, che inizia con la riga 1. Quindi la riga di comando legge 'file' e quando il numero di riga è uguale a 4, stampa quella riga seguita da qualunque cosa tu voglia iniettare.

Mi affretto ad aggiungere che Perl deve le sue radici a sed, AWK e C, quindi la sintassi per semplici sostituzioni, ecc. Non è una curva di apprendimento molto ripida.


Bella risposta! Ma puoi semplificarlo un po '. Prova questo: perl -wlpi.old -e 'print "mode 0755" if $. == 5' file.txt. Lo -pswitch funziona bene qui (poiché vogliamo stampare ogni riga); non ci resta che cambiare la logica da "stampa dopo la riga 4" a "stampa prima della riga 5". E l' -linterruttore fa in modo che "\ n" venga stampato automaticamente con ogni print, quindi non è necessario stamparlo da soli.
JL,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.