sed
BSD / macOS Sed vs. GNU Sed rispetto alla specifica POSIX Sed
Ricerca…
introduzione
Per citare la richiesta di creazione dell'argomento di @ SnoringFrog:
"Uno dei trucchi più grandi che utilizzano sed è quello degli script che non riescono (o che riescono in un modo inaspettato) perché sono stati scritti per uno e non per l'altro." Un semplice run-down delle differenze più importanti sarebbe positivo. "
Osservazioni
macOS usa la versione BSD di sed [1] , che differisce sotto molti aspetti dalla versione sed GNU fornita con distribuzioni Linux .
Il loro comune denominatore è la funzionalità decretata da POSIX : vedi le specifiche POSIX sed .
L' approccio più portabile è quello di utilizzare solo le funzionalità POSIX , che, tuttavia, limita la funzionalità :
In particolare, POSIX specifica il supporto solo per le espressioni regolari di base , che hanno molte limitazioni (ad esempio, nessun supporto per
|(alternanza), nessun supporto diretto per+e?) E diversi requisiti di escape.- Caveat: GNU
sed(senza-r), supporta\|,\+e\?, che NON è conforme a POSIX; usa--posixper disabilitare (vedi sotto).
- Caveat: GNU
Per utilizzare solo le funzioni POSIX :
(entrambe le versioni): usa solo le opzioni
-ne-e(in particolare, non utilizzare-Eo-rper attivare il supporto per le espressioni regolari estese )GNU
sed: aggiungi l'opzione--posixper garantire le funzionalità POSIX-only (non è strettamente necessario, ma senza di essa potresti finire inavvertitamente usando funzionalità non POSIX senza accorgertene; avvertimento :--posixstesso non è conforme a POSIX )L'uso di funzionalità POSIX significa requisiti di formattazione più rigidi (per rinunciare a molte comodità disponibili in GNU
sed):- Le sequenze di caratteri di controllo come
\ne\tgeneralmente NON sono supportate. - Etichette e comandi di diramazione (ad esempio,
b) deve essere seguita da una nuova riga effettiva o prosecuzione tramite un separato-eopzione. - Vedi sotto per i dettagli.
- Le sequenze di caratteri di controllo come
Tuttavia, entrambe le versioni implementano le estensioni dello standard POSIX:
- quali estensioni implementano differisce (GNU
sedimplementa di più). - anche quelle estensioni che entrambi implementano differiscono parzialmente nella sintassi .
Se è necessario supportare le piattaforme ENTRAMBI (discussione delle differenze):
Caratteristiche incompatibili :
L'uso dell'opzione
-isenza argomento (aggiornamento sul posto senza backup) non è compatibile:- BSD
sed: DEVE usare-i '' - GNU
sed: DEVE usare solo-i(equivalente:-i'') - usare-i ''NON funziona.
- BSD
-iattiva sensibilmente la numerazione delle righe per file di input nelle versioni GNUsede recenti di BSDsed(ad esempio, su FreeBSD 10), ma NON su macOS a partire dal 10.12 .
Si noti che in assenza di-inumeri di tutte le versioni del numero cumulativo tra i file di input.Se l' ultima riga di input non ha una nuova riga finale (e viene stampata):
- BSD
sed: aggiunge sempre una nuova riga sull'output, anche se la riga di input non finisce in uno. - GNU
sed: conserva lo stato di fine riga finale , cioè aggiunge una nuova riga solo se la riga di input termina in una.
- BSD
Caratteristiche comuni :
- Se si limitano i propri script
seda ciò che supporta BSDsed, generalmente funzioneranno anche in GNUsed, con la notevole eccezione dell'utilizzo di funzionalità regex estese specifiche della piattaforma con-E. Ovviamente, perderai anche estensioni specifiche per la versione GNU. Vedi la prossima sezione.
- Se si limitano i propri script
Linee guida per il supporto multipiattaforma (OS X / BSD, Linux), guidato dai requisiti più severi della versione BSD :
Si noti che che le abbreviazioni MacOS e Linux sono a volte utilizzati di seguito per riferirsi alle versioni BSD e GNU di sed rispettivamente, perché sono le versioni azionari su ogni piattaforma. Tuttavia, è possibile installare GNU sed su macOS, ad esempio, usando Homebrew con brew install gnu-sed .
Nota : Tranne quando vengono utilizzati i flag -r e -E (regex estesi ), le istruzioni riportate di seguito equivalgono alla scrittura di script sed conformi a POSIX .
Per conformità con POSIX, è necessario limitarsi a POSIX BREs (espressioni regolari di base ) , che sono, sfortunatamente, come suggerisce il nome, piuttosto semplici.
Avvertenza : non dare per scontato che\|,\+e\?sono supportati: Mentre GNUsedli supporta (a meno che non--posixusato--posix), BSDsedno - queste funzionalità non sono conformi a POSIX.
Mentre\+e\?può essere emulato in modo conforme a POSIX:
\{1,\}per\+,
\{0,1\}per\?,
\|(alternanza) non può , sfortunatamente.Per espressioni regolari più potenti, usare
-E(piuttosto che-r) per supportare ERE (espressioni regolari estese ) (GNUsednon documenta-E, ma funziona lì come alias di-r; versione più recente di BSDsed, come su FreeBSD 10, ora supporta anche-r, ma la versione macOS a partire da 10.12 non lo fa).
Avvertenza : anche se l'uso di-r/-Esignifica che il comando è per definizione non conforme a POSIX, è comunque necessario limitarsi a POSIX ERE (espressioni regolari estese) . Purtroppo, questo significa che non sarai in grado di utilizzare diversi costrutti utili, in particolare:- asserzioni di parole-limite, perché sono specifiche della piattaforma (ad esempio,
\<su Linux,[[:<]]su OS X). - back-reference all'interno di espressioni regolari (al contrario dei "back-references" alle partite del gruppo di cattura nella stringa di sostituzione delle chiamate di funzione
s), perché BSDsednon li supporta nelle espressioni regolari estese (ma, curiosamente, lo fa in quelli di base , dove sono assegnati da POSIX).
- asserzioni di parole-limite, perché sono specifiche della piattaforma (ad esempio,
Sequenze di escape di caratteri di controllo come
\ne\t:In regex (sia nei pattern per la selezione delle linee che nel primo argomento della funzione
s), supponiamo che solo\nsia riconosciuta come una sequenza di escape (usata raramente, dato che lo spazio pattern è solitamente una singola riga (senza terminare\n), ma non all'interno di una classe di caratteri , in modo che, ad esempio,[^\n]non funzioni, (se il tuo input non contiene caratteri di controllo diversi da\t, puoi emulare[^\n]con[[:print:][:blank:]]; in caso contrario, i caratteri di controllo splice. come letterali [2] ), in genere includono i caratteri di controllo come letterali , sia tramite stringhe con quoting ANSI con splicing- c (es.$'\t') in shell che lo supportano (bash,ksh,zsh) o tramite sostituzioni di comando usandoprintf(ad es."$(printf '\t')") .- Solo Linux:
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b' - OSX e Linux:
sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
- Solo Linux:
Nelle stringhe di sostituzione utilizzate con il comando
s, si supponga che non siano supportate sequenze di escape di caratteri di controllo , quindi, di nuovo, includere i caratteri di controllo. come letterali , come sopra.- Solo Linux:
sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b' - macOS e Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Solo Linux:
Idem per gli argomenti di testo per
ieafunzione : non usare sequenze di caratteri di controllo - vedi sotto.
Etichette e ramificazioni : le etichette e l' argomento nome-etichetta delle funzioni
betdevono essere seguite da una nuova riga letterale o da un$'\n'. In alternativa, utilizzare più opzioni-ee terminare ogni destra dopo il nome dell'etichetta.- Solo Linux:
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a' - macOS e Linux:
- EITH (newlines attuali):
sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb' - OR (istanze
$\nimpiombate):
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb' - OPPURE (più opzioni
-e):
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- EITH (newlines attuali):
- Solo Linux:
Funzioni
ieaper inserire / accodare il testo : segui il nome della funzione con\, seguito da una nuova riga letterale o da un$'\n'spliced-in prima di specificare l'argomento di testo.- Solo Linux:
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b' - OSX e Linux:
sed -e '1 i\'$'\n''new first line' <<<$'a\nb' - Nota:
- Senza
-e, l'argomento text è inspiegabilmente non newline-terminated sull'output su macOS (bug?). - Non utilizzare gli escape di caratteri di controllo come
\ne\tnell'argomento di testo, poiché sono supportati solo su Linux. - Se l'argomento del testo ha quindi una nuova linea interna,
\-escape. - Se vuoi inserire comandi addizionali dopo l'argomento text, devi terminarlo con una newline (senza caratteri di escape) (sia letterale che spliced in), o continuare con un'opzione
-eseparata (questo è un requisito generale che si applica a tutte le versioni) .
- Senza
- Solo Linux:
All'interno degli elenchi delle funzioni (chiamate a funzioni multiple racchiuse in
{...}), assicurarsi di terminare anche l' ultima funzione, prima della chiusura}, con;.- Solo Linux:
-
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
-
- macOS e Linux:
-
sed -n '1 {p;q;}' <<<$'a\nb'
-
- Solo Linux:
Caratteristiche specifiche di GNU sed mancanti di BSD sed tutto:
Funzionalità GNU che ti perderai se hai bisogno di supportare entrambe le piattaforme:
Varie opzioni di corrispondenza regolare e di sostituzione (sia nei modelli per la selezione della linea che il primo argomento della funzione
s):- L'opzione
Iper la corrispondenza delle espressioni regolari case-INsensitive (incredibilmente, BSDsednon supporta affatto questo). - L'opzione
Mper la corrispondenza multilinea (dove^/$corrisponde all'inizio / fine di ogni riga ) - Per ulteriori opzioni specifiche per la funzione
s, consultare https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
- L'opzione
Sequenze di fuga
Sequenze di escape relative alla sostituzione come
\unell'argomento di sostituzione della funziones///che consentono la manipolazione della sottostringa , entro i limiti; ad esempio,sed 's/^./\u&/' <<<'dog' # -> 'Dog'- vedi http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022 -ComandoSequenze di escape del carattere di controllo: oltre a
\n,\t, ..., escape basato su punti di codice; per esempio, tutti i seguenti escape (es., ottale, decimale) rappresentano una singola citazione ('):\x27,\o047,\d039- vedi https://www.gnu.org/software/sed/manual/ sed.html # Escapes
Estensioni di indirizzi , come ad esempio
first~stepper abbinare ogni step-th line,addr, +Nper abbinare N lines dopoaddr, ... - vedi http://www.gnu.org/software/sed/manual/sed. html # Indirizzi
[1] La versione macOS sed è più vecchia della versione su altri sistemi simili a BSD come FreeBSD e PC-BSD. Sfortunatamente, questo significa che non puoi assumere che le funzionalità che funzionano in FreeBSD, ad esempio, funzionino [lo stesso] su macOS.
[2] Stringa quotata da ANSI C $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' contiene tutti i caratteri di controllo ASCII tranne \n (e NUL), quindi puoi usarlo in combinazione con [:print:] per un'emulazione abbastanza robusta di [^\n] :
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']
Sostituisci tutte le nuove righe con le schede
Nota: per brevità, i comandi usano stringhe quotate qui ( <<< ) e ANSI C ( $'...' ) . Entrambe queste funzioni della shell funzionano in bash , ksh e zsh .
# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3
# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'
# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'
Note di BSD Sed:
Notare la necessità di terminare le etichette (
:a) e i comandi di diramazione (ba) con le nuove righe effettive o con opzioni-eseparate.Poiché le sequenze di escape dei caratteri di controllo come
\tnon sono supportate nella stringa di sostituzione, un letterale di tabulazione C quotato ANSI è giuntato nella stringa di sostituzione.
(Nella parte regex , BSD Sed riconosce solo\ncome sequenza di escape).
Aggiungi testo letterale a una riga con la funzione 'a'
Nota: per brevità, i comandi usano stringhe quotate qui ( <<< ) e ANSI C ( $'...' ) . Entrambe queste funzioni della shell funzionano in bash , ksh e zsh .
# GNU Sed
$ sed '1 a appended text' <<<'line 1'
line 1
appended text
# BSD Sed (multi-line form)
sed '1 a\
appended text' <<<'line 1'
# BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
sed $'1 a\\\nappended text' <<<'line 1'
Si noti come BSD Seed richiede un \ seguito da una nuova riga effettiva per passare il testo da aggiungere.
Lo stesso vale per le funzioni i (inserimento) e c (cancella e inserisci) correlate.