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).
  • 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.

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.
    • -i attiva sensibilmente la numerazione delle righe per file di input nelle versioni GNU sed e recenti di BSD sed (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.
  • Caratteristiche comuni :

    • Se si limitano i propri script sed a ciò che supporta BSD sed , generalmente funzioneranno anche in GNU sed , 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.

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 GNU sed li supporta (a meno che non --posix usato --posix ), BSD sed 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 ) (GNU sed non documenta -E , ma funziona lì come alias di -r ; versione più recente di BSD sed , 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é BSD sed non li supporta nelle espressioni regolari estese (ma, curiosamente, lo fa in quelli di base , dove sono assegnati da POSIX).
  • 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 usando printf (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
    • 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'
    • Idem per gli argomenti di testo per i e a funzione : non usare sequenze di caratteri di controllo - vedi sotto.

  • Etichette e ramificazioni : le etichette e l' argomento nome-etichetta delle funzioni b e t 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'
  • Funzioni i e a 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) .
  • 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'

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, BSD sed 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
  • Sequenze di fuga

  • Estensioni di indirizzi , come ad esempio first~step per abbinare ogni step-th line, addr, +N per abbinare N lines dopo addr , ... - 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.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow