Modo migliore per fare "echo $ x | sed ... "e" echo $ x | grep ... "


14

Lo trovo spesso negli script (e, devo ammetterlo, scrivo da solo):

a=$(echo "$x" | sed "s/foo/bar/")

o

if echo "$x" | grep -q foo
then
    ...
fi

Considera "pippo" per includere alcune cose regex.

Sento che dovrebbe esserci - e molto probabilmente lo è - un modo migliore per esprimerlo, uno che non coinvolge due comandi e una pipe ma avvolge la cosa in un'espressione più compatta.

Non riesco proprio a trovarlo. Chiunque?


mi aspetto che questa espressione venga usata frequentemente a causa di una combinazione di ignoranza (non conoscere le alternative) e manutenibilità (conoscere le alternative ma scegliere questa come la più semplice da capire). posso dire a colpo d'occhio cosa fanno i tuoi esempi, ma ho bisogno di un riferimento shell per capire le alternative nelle risposte di Grawity e Dan McG.
Quack Quixote

3
A proposito, il metodo preferito per eseguire la sostituzione dei comandi è con $()piuttosto che con i backtick.
In pausa fino a ulteriore avviso.

2
È anche una buona idea citare le espansioni in modo da proteggere gli spazi bianchi: a="$(echo "$x" | sed "s/foo/bar/")"e if echo "$x" | grep foo; ….
Chris Johnsen,

Buone osservazioni su $ () vs. ``. Vedo che le mie abilità bash non sono ancora così grandi.
DevSolar

Risposte:


12

A meno che non si assuma una shell specifica, non esiste un modo migliore per farlo di "pipe echo to tool" (o solo uno "strumento" stesso come expr ); è tutto ciò su cui puoi davvero contare con la tradizionale shell Bourne e / o la shell POSIX . Se si considerano altre shell, ci sono altre possibilità integrate.

ksh ha

  • Modelli extra: ?(pattern-list), *(pattern-list), {n}(pattern-list), {n,m}(pattern-list), @(pattern-list), !(pattern-list),
  • l' %P identificatore printf per convertire un'espressione regolare estesa in un modello (e %Rper l'espressione regolare estesa in modello);
  • la expr == patterncondizione nei [[ expr ]]test;
  • l' ${param/pattern/replacement}espansione dei parametri.

bash ha

  • l' extglobopzione per abilitare la maggior parte dei pattern extra di ksh (no {n}e {n,m});
  • la expr == patterncondizione (nei [[ expr ]]test);
  • l' ${param/pattern/replacement}espansione dei parametri;
  • (nelle versioni più recenti) la expr =~ extregexpcondizione (nei [[ expr ]]test) che può corrispondere a espressioni regolari estese
    • con le sottoespressioni tra parentesi e il BASH_REMATCHparametro, è possibile eseguire sostituzioni in stile sed .

zsh ha

  • i suoi modelli estesi con l' EXTENDED_GLOBopzione;
  • modelli estesi simili a ksh con l' KSH_GLOBopzione;
  • la expr == patterncondizione (nei [[ expr ]]test);
  • l' ${pattern/pattern/replacement}espansione dei parametri;
  • la expr =~ extregexpcondizione (nei [[ expr ]]test) che può corrispondere a espressioni regolari estese,
    • può utilizzare PCRE anziché semplici espressioni regolari estese se è impostata l'opzione RE_MATCH_PCRE,
    • con le sottoespressioni tra parentesi, il MATCHparametro e il matchparametro (o BASH_REMATCHcon l' BASH_REMATCHopzione impostata), è possibile eseguire sostituzioni in stile sed ;
  • il zsh/pcremodulo che offre pcre_compile, pcre_studye pcre_matchcomandi e la condizione di -pcre-match test (nei [[ expr ]]test);
  • il zsh/regexmodulo che offre la condizione di -regex-match test (nei [[ expr ]]test).

Wow. Completo come si potrebbe desiderare. Sicuramente un vincitore.
DevSolar

6

Per sostituire la linea sed, fai qualcosa di simile

${a/foo/bar} o ${a//foo/bar}

Nel primo modulo, viene sostituita solo la prima istanza. Il secondo modulo è una ricerca globale e sostituisci.

Nel tuo caso, lo sarebbe

Invece di:

if echo $x | grep foo
then
    ...
fi

Prendi in considerazione l'utilizzo di:

if [ $x =~ foo ]
then
    ...
fi

Dov'è fooun'espressione regolare.


In quali shell funziona?
Peltier,

1
if [ $x =~ foo ]dà un messaggio di errore qui. if [[ $x =~ foo ]], tuttavia, funziona alla grande. Grazie!
DevSolar

1
Tutti questi sono bashismi, richiedono bash. Inoltre, =~richiede bash> = 3 iirc.
ℝafink

1
Inoltre, foo non è un'espressione regolare (come in PCRE) in questi esempi, ma usa caratteri jolly. C'è di più di questi bontà bash nella manpage bash, sezione "Parameter Expansion". Apprezzo in particolare cose come ${a##foo}e ${a%%bar}.
inkafink

3
L'operatore di corrispondenza =~utilizza espressioni regolari. Questo è vero, ad esempio: [[ "abcdddde" =~ ^a.*d+.g* ]](questo è zero o più g, invece di g-jolly, per esempio).
In pausa fino a ulteriore avviso.

2

Un buon modo compatibile posix per testare se una variabile contiene un modello è:

test ${var##*foo*} || <do something>;

La sintassi dell'espansione dei parametri è:

 ${parameter##pattern}

dove patternè un modello di conchiglia .

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.