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--posix
per disabilitare (vedi sotto).
- Caveat: GNU
Per utilizzare solo le funzioni POSIX :
(entrambe le versioni): usa solo le opzioni
-n
e-e
(in particolare, non utilizzare-E
o-r
per attivare il supporto per le espressioni regolari estese )GNU
sed
: aggiungi l'opzione--posix
per garantire le funzionalità POSIX-only (non è strettamente necessario, ma senza di essa potresti finire inavvertitamente usando funzionalità non POSIX senza accorgertene; avvertimento :--posix
stesso 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
\n
e\t
generalmente NON sono supportate. - Etichette e comandi di diramazione (ad esempio,
b
) deve essere seguita da una nuova riga effettiva o prosecuzione tramite un separato-e
opzione. - 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
sed
implementa 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
-i
senza 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
-i
attiva sensibilmente la numerazione delle righe per file di input nelle versioni GNUsed
e recenti di BSDsed
(ad esempio, su FreeBSD 10), ma NON su macOS a partire dal 10.12 .
Si noti che in assenza di-i
numeri 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
sed
a 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 GNUsed
li supporta (a meno che non--posix
usato--posix
), BSDsed
no - 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 ) (GNUsed
non 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
/-E
significa 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é BSDsed
non 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
\n
e\t
:In regex (sia nei pattern per la selezione delle linee che nel primo argomento della funzione
s
), supponiamo che solo\n
sia 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
i
ea
funzione : non usare sequenze di caratteri di controllo - vedi sotto.
Etichette e ramificazioni : le etichette e l' argomento nome-etichetta delle funzioni
b
et
devono essere seguite da una nuova riga letterale o da un$'\n'
. In alternativa, utilizzare più opzioni-e
e 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
$\n
impiombate):
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
i
ea
per 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
\n
e\t
nell'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
-e
separata (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
I
per la corrispondenza delle espressioni regolari case-INsensitive (incredibilmente, BSDsed
non supporta affatto questo). - L'opzione
M
per 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
\u
nell'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~step
per abbinare ogni step-th line,addr, +N
per 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-e
separate.Poiché le sequenze di escape dei caratteri di controllo come
\t
non 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\n
come 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.