per quanto riguarda sed -e portatile ... db o! B?


12

In questa modifica Stéphane Chazelas POSIXifica (di nuovo) la mia sedformattazione inserendo una -epausa xpression e un'altra -edichiarazione xpression. Ora, potrei solo chiedergli perché nei commenti, suppongo, ma è già la revisione numero 18 su quella risposta e quasi tutti i precedenti erano già grazie a omaggi simili (se riesci a vedere i commenti cancellati saprai cosa Intendo) . Inoltre, penso di essere abbastanza vicino per capire perché esprimerlo in un modo che potrebbe essere più generalmente utile. Quindi spero ...

In genere preferisco mantenere le mie sed -expressioni totali su una se potessi, ma ho anche una maggiore preferenza per conformarmi alle specifiche il più vicino possibile, specialmente quando la differenza non è maggiore di a <space>e an -e. Ma non posso farlo se non capisco perché dovrei. Ecco un breve riassunto dello stato attuale della mia comprensione:

  • l' ' -e 'interruzione può portare in modo portabile a un'interruzione di ewline dello sedscript in \nun'istruzione della sedriga di comando ... Sono certo sfocata sul perché

  • la parentesi graffa di chiusura in una sed {funzione }deve essere preceduta da un'interruzione di \newline come indicato qui:

    • Il <right-brace>è preceduta da una <newline>e può essere preceduta o seguita da <blank>caratteri.
  • una \npausa ewline è altrettanto necessario in seguito a qualsiasi uso di ... a, b, c, i, r, t, w, o :.

Ma non capisco chiaramente in che modo la definizione della {funzione si }riferisce !all'operatore non. L'unica menzione che trovo dell'operatore di negazione negli stati delle specifiche:

  • Una funzione può essere preceduta da uno o più !caratteri, nel qual caso la funzione deve essere applicata se gli indirizzi non selezionano lo spazio del modello.

Questo significa che l'uso di un !implica {parentesi graffe }? Che $!dire dei comandi - dovrebbero anche essere separati da ' -e 'interruzioni? È stato questo ciò che è stato affrontato quando Stéphane ha recentemente posto la mia risposta?

Penso che sia l' !operatore di negazione, o è la bdichiarazione del ranch che affronta nella sua modifica - o forse è entrambi contemporaneamente - ma non lo so e mi piacerebbe. Se è solo la bdichiarazione del ranch, allora credo che un dfarebbe al suo posto ed eliminerebbe la necessità dell'interruzione ' -e ', ma preferirei essere certo prima di mettere in pericolo una risposta POSIXified tre volte . Puoi aiutare?

Dopo tutto , l' ho rischiato , ma non con grande certezza ...


Con b;n;:b, stai ramificando l'etichetta chiamata ";n;:b"in seds storiche e POSIX (e GNU sed non è a questo proposito).
Stéphane Chazelas,

@ StéphaneChazelas - Ricevo la :parte - hai guidato quella casa mesi fa. Ma non capisco perfettamente perché il secondo sedcomando sia stato similmente POSIXificato .
Mikeserv,

1
In ogni caso, le specifiche POSIX per non sedsono molto chiare per me. Ho chiesto chiarimenti alcune volte in passato, ma non credo che sia stato aggiornato di conseguenza. Un buon test è quello di provare con il toolchest cimelio (Solaris, derivato dall'originale e su cui si basa ampiamente la specifica POSIX).
Stéphane Chazelas,

1
@syntaxerror - non credo proprio che sia così. se leggi le specifiche scoprirai che le s///istituzioni dovrebbero accettare il concatenamento con a ; . diventa sfocato attorno ai comandi che devono essere delimitati con una nuova riga e come -epuò resistere in quel caso - almeno lo fa per me. Vivo ancora per inciampare su un sedche non li interpreta in modo abbastanza intercambiabile però.
Mikeserv,

1
@syntaxerror - Mi piace, ma dovresti sapere che non hai bisogno di ;prima di una nuova riga - una nuova riga va bene. Onestamente, si potrebbe fare a meno del -ee tutto interamente e solo scrivere un file come #!/bin/sedcon ogni comando su una nuova riga - o quelli che non richiedono tali delimitatori invece delimitati con ;. Quelli che fare richiedono nuove righe sono di solito quelli che prendono ingresso arbitrari - :nomi delle etichette e comandi che si riferiscono a loro come bo to chiusura }graffe per funzioni o read e writo che prendono args nomi di file. Devono essere seguiti tutti in modo portabile \n.
Mikeserv

Risposte:


4

Quindi è giunto il momento che questa domanda abbia una risposta e, anche se alla fine ho capito intuitivamente come farlo correttamente in quasi tutti i casi qualche tempo fa, solo molto recentemente sono riuscito a capire abbastanza concretamente questa comprensione con il testo nello standard . In realtà è dichiarato lì abbastanza semplicemente - l'ho semplicemente stupidamente trascurato molte volte, immagino.

Le parti pertinenti del testo si trovano tutte sotto l'intestazione ...

  • Comandi di modifica insed :

    • Il testo dell'argomento deve consistere in una o più righe. Ogni \newline incorporata nel testo deve essere preceduta da una \barra rovesciata. Le altre barre rovesciate nel testo devono essere rimosse e il seguente carattere deve essere trattato alla lettera.

    • I verbi del comando re w, e il wflag al scomando, accettano un parametro rfile (o wfile ) opzionale , separato dalla lettera o flag del verbo del comando da uno o più <blank>s; le implementazioni possono consentire la separazione zero come estensione.

    • Comando verbi diverso {, a, b, c, i, r, t, w, :, e #può essere seguito da una ;virgola, opzionale <blank>s, e un altro verbo di comando. Tuttavia, quando il sverbo di comando viene utilizzato con il wflag, seguirlo con un altro comando in questo modo produce risultati indefiniti.

...nel...

  • Opzioni: Molteplici -ee -fopzioni possono essere specificate. Tutti i comandi devono essere aggiunti allo script nell'ordine specificato, indipendentemente dalla loro origine.

    • -e script - Aggiungi i comandi di modifica specificati dall'opzione- script script alla fine dello script dei comandi di modifica. L' argomento dell'opzione di script deve avere le stesse proprietà dell'operando di script , descritto nella sezione OPERANDS .

    • -f script_file - Aggiungi i comandi di modifica nel file script_file alla fine dello script.

E ultimo in ...

  • operandi:

    • script - Una stringa da utilizzare come script di comandi di modifica. L'applicazione non deve presentare uno script che viola le restrizioni di un file di testo, tranne per il fatto che il carattere finale non deve necessariamente essere una \newline.

Quindi, quando lo prendi del tutto, ha senso che qualsiasi comando che è facoltativamente seguito da un parametro arbitrario senza un delimitatore predefinito (al contrario di s d sub d repl d flagper esempio) dovrebbe delimitare in una \newline senza escape.

È discutibile che si ; tratti di un delimitatore predefinito, ma in quel caso l'uso ;di uno dei [aic]comandi richiederebbe che un parser separato fosse incluso nell'implementazione specificamente per quei tre comandi - separato, cioè dal parser usato [:brw]per esempio. Altrimenti l'implementazione dovrebbe richiedere che ; anche la barra rovesciata venga salvata all'interno del parametro text e da quel momento in poi diventa più complicata.

Se stavo scrivendo un messaggio sedche desideravo essere sia conforme che efficiente, quindi non scriverei un parser così separato, mi aspetto - tranne che forse [aic]dovrebbe generare un errore di sintassi se non immediatamente seguito da una \newline. Ma questo è un semplice problema di tokenizzazione: il caso del delimitatore finale è generalmente il più problematico. Lo scriverei così:

sed -e w\ file\\ -e one -e '...;and more commands'

...e...

sed -e a\\ -e appended\\ -e text -e '...;and more commands'

... si comporterebbe in modo molto simile, in quanto il primo creerebbe e scriverà in un file chiamato:

file
one

... e il secondo aggiungerebbe un blocco di testo alla riga corrente in uscita come ...

appended
text

... perché entrambi condividono lo stesso codice di analisi per il parametro.

E per quanto riguarda l' { ... }e $!problema - beh, io ci ero lontano. Un singolo comando preceduto da un indirizzo non è una funzione ma piuttosto è solo un comando indirizzato. Quasi tutti i comandi - inclusa la { definizione della funzione } sono specificati per accettare /one/o /one/,/two/indirizzi - ad eccezione della definizione di #commento e :etichetta . E un indirizzo può essere un numero di riga o un espresso normale e può essere negato !. Quindi tutto ...

$!d
/address/s/ub/stitution/
5!y/d/c/

... possono essere seguiti da uno ;e più comandi secondo lo standard, ma se sono richiesti più comandi per un singolo indirizzo e tale indirizzo non deve essere rivalutato dopo l'esecuzione di ciascun comando, allora una {funzione }dovrebbe essere usata come:

/address/{ s//replace addressed pattern/
           s/do other conditional/substitutions/
           s/in the same context/without/
           s/reevaluating/address/
}

... dove {non può essere seguito sulla stessa linea da una chiusura }e che una chiusura }non può avvenire se non all'inizio di una linea. Ma se un comando contenuto non dovrebbe altrimenti essere seguito da una \newline, non è nemmeno necessario che sia all'interno della funzione. Quindi tutte le precedenti s///sostituzioni - e persino il }controvento di chiusura , possono essere seguite in modo portabile da ;punti e virgola e da altri comandi.

Continuo a parlare di \ndelimitatori di ewline ma la domanda riguarda invece le -edichiarazioni di xpression, lo so. Ma i due sono davvero la stessa cosa, e la relazione chiave è che uno script può essere un argomento letterale da riga di comando o un file con uno dei due -[ef], e che entrambi sono interpretati come file di testo (che sono specificati per terminare in un \newline) ma nessuno dei due deve effettivamente finire in una \newline. Con ciò posso ragionevolmente (spero) dedurre che un \0NULargomento delimitato implica una fine \newline, e dato che tutti gli argomenti di invocazione ottengono almeno) un \0NULdelimitatore comunque, allora entrambi dovrebbero funzionare bene.

In effetti, in pratica, in ogni caso, tranne uno in cui lo standard specifica una \barra rovesciata, deve essere richiesta una nuova barra rovesciata, ho scoperto che ...

sed -e ... -e '...\' -e '...'

... per funzionare altrettanto bene. E in ogni caso - di nuovo, in pratica - dove \ndovrebbe essere richiesta una ewline non fuggita ...

sed -e '...' -e '...'

... ha funzionato anche per me. L'unica eccezione che menziono sopra è ...

sed -e 's/.../...\' -e '.../'

... che non funziona per nessuna implementazione in nessuno dei miei test. Sono abbastanza sicuro che ricade sul requisito del file di testo e sul fatto che s/// viene fornito con un delimitatore e quindi non vi è alcun motivo per cui una singola istruzione dovrebbe comprendere \0NULargomenti delimitati.

Quindi, in conclusione, ecco una breve carrellata di modi portatili per scrivere diversi tipi di sedcomandi:

Per uno qualsiasi di [aic]:

...commands;[aic]\
text embedded newline\
delimiting newline
...more;commands...

...o...

sed -e '...commands;[aic]\' -e 'text embedded newline\' -e 'delimiting newline' -e '.;.;.'

Per ognuno dei casi in [:rwtb]cui il parametro è facoltativo (per tutti, ma :), ma la \newline di delimitazione non lo è . Si noti che non ho mai avuto motivo di provare i parametri dell'etichetta a più righe come verrebbero utilizzati [:tb], ma che il writing / read di più righe nei parametri del file [rw] è di solito accettato senza dubbio da seds che ho testato fino a quando la \newline incorporata è sfuggito con una \barra rovesciata. Tuttavia, lo standard non specifica direttamente che i parametri del file label e [rw] debbano essere analizzati in modo identico al testoparametri e non fa menzione delle \newline relative ai primi due, tranne se li delimita.

...commands;[:trwb] parameter
...more;commands...

...o...

sed -e '[:trwb] parameter' -e '...'

... dove quanto <space>sopra è facoltativo per [:tb].

E ultimo...

...;address[!]{ ...function;commands...
};...more;commands....

...o...

sed -e '...;address[!]{ ...function;commands...' -e '};...more;commands...'

... dove uno qualsiasi dei comandi sopra menzionati (eccetto :) accetta anche almeno un indirizzo e che può essere un /regexp /o un numero di riga e potrebbe essere negato !, ma se è necessario più di un comando per una singola valutazione dell'indirizzo, allora È necessario utilizzare le parentesi graffe che delimitano il {contesto della funzione }. Una funzione può contenere anche più \ncomandi delimitati da ewline, ma ognuno deve essere delimitato tra parentesi graffe come sarebbe altrimenti.

Ed ecco come scrivere sedscript portatili .


2
Perché non accetti la tua risposta?
Philippos,
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.