Come trovare e sostituire la stringa senza usare il comando Sed?


16

Come tutti sappiamo, sedè molto efficace per trovare e sostituire stringhe, ad esempio find 'a' e sostituirlo a 'b': sed 's/a/b/g'.

È possibile farlo con altri comandi o script shell invece di sed?

Questo è per un sistema Linux ritagliato per la TV che non ha il sedcomando. Quindi devo usare altri comandi o script invece dised 's/a/b/g'. –


In realtà, questa è solo una sostituzione basata su espressioni regolari. Qualsiasi strumento o linguaggio in grado di gestire tale cosa saranno in grado di fare lo stesso, ma con varie sintassi: $var=~s/a/b/g, gsub(/a/,"b",var), var.gsub(/a/,'b'), var.replace(/a/g,'b'), preg_replace("/a/","b",$var), regsub -all a b $var. Inoltre, molti strumenti e lingue possono anche eseguire la sostituzione di stringhe di testo semplice. Quindi la tua domanda è in qualche modo ampia.
arte

1
Perché? Che problema stai cercando di risolvere?
Gilles 'SO- smetti di essere malvagio' il

Un sistema Linux ritagliato per la TV non ha il comando sed. Quindi devo usare altri comandi o script invece di sed 's / a / b / g'.
binghenzq,

Risposte:


12

Sì, ci sono molti modi per farlo. Puoi usare awk, perlo anche bashper fare queste attività. In generale, tuttavia, sedè probabilmente lo strumento più indicato per svolgere questo tipo di attività.

Esempi

Supponiamo di avere questi dati di esempio, in un file data.txt:

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Perl

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Modifica in linea

Gli esempi sopra possono anche modificare direttamente i file. L'esempio Perl è banale. Aggiungi semplicemente l' -iinterruttore.

$ perl -pie "s/foo/foofoofoo/g" data.txt 

Perché awkè un po 'meno diretto ma altrettanto efficace:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

Questo metodo crea una sotto-shell con le parentesi graffe '{...} `in cui il file viene reindirizzato al suo interno tramite questo:

$ { ... } < data.txt

Una volta che il file è stato reindirizzato nella sotto-shell, viene eliminato e quindi awkeseguito sul contenuto del file letto nella sotto-shell STDIN. Questo contenuto viene quindi elaborato awke riscritto con lo stesso nome file che abbiamo appena eliminato, sostituendolo efficacemente.


Grazie per la tua risposta e lo proverò il giorno lavorativo successivo. Ma non sono sicuro che funzioni perché alcuni comandi potrebbero non esistere in un sistema Linux TV ritagliato, come 'sed'. Quindi voglio ancora usare il comando 'trova' , 'grep' e così via per risolverlo.
binghenzq,

@binghenzq - Ho aggiunto esempi che incorporano la modifica del file.
slm

-1 Raramente voto negativo ma in questo caso il punto della domanda sembrava essere un metodo più semplice piuttosto che altri più / ugualmente complessi e probabilmente anche dipendenti. Se la domanda riguardasse solo le alternative per l'installazione di una macchina * nix completa, probabilmente farei +1 su questa risposta altrimenti buona.
Michael Durrant,

@MichaelDurrant - Ho appena aggiunto quelle elaborate modifiche in linea b / c richieste dall'OP. Anche il PO ha stabilito il requisito di NON usare sednon I. Sed è lo strumento appropriato per fare sostituzioni come questa, e ovviamente sta chiedendo di capire meglio i ruoli di questi strumenti, quindi mostrare a qualcuno queste cose seppur male, è estremamente educativo nel mostrare loro perché. Troppe volte il ppl nel sapere semplicemente dice "non farlo" senza spiegare il perché, quindi lo sono. Ma grazie almeno per aver lasciato un commento sul perché DV.
slm

Certo, ho pensato che fosse un'ottima risposta sotto tutti gli altri aspetti. sì, odio -1 senza spiegazioni.
Michael Durrant,

13

La classica alternativa per le sostituzioni a lettera singola è il trcomando che dovrebbe essere disponibile su quasi tutti i sistemi:

$ echo "foobar" | tr a b   
foobbr

trè meglio che sedper questo in realtà poiché usare sed(figuriamoci perlo awk) per le sostituzioni di una sola lettera è come usare un martello per uccidere una mosca.

grep non è progettato per questo, non modifica il suo input, cerca solo attraverso di esso.

In alternativa, è possibile utilizzare le funzionalità di sostituzione di alcune shell. Qui usando ksh, zsho bashsintassi:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

Potremmo darti risposte più specifiche se spiegassi esattamente quale problema stai cercando di risolvere.


Esiste un'opzione per ignorare il caso ${foo//a/b}?
AlikElzin-Kilaka,

@ AlikElzin-kilaka, temo di no. Dovrete usare qualcosa di più sofisticato, come, ad esempio: echo "$foo" | sed 's/a/b/io dare una classe di caratteri: echo ${foo//[aA]/b}.
terdon

4

Puoi usare Vim in modalità Ex:

ex -s -c '%s/a/b/g|x' file
  1. % seleziona tutte le righe

  2. s sostituto

  3. g sostituzione globale

  4. x salva e chiudi


grazie mille. solo per aggiungere, -c flag è quello di eseguire il comando quando inizia la modifica (dato che ex è un editor) e -s flag è la modalità script che disabilita il feedback o come alcuni preferiscono dire slient-mode. riferimento per maggiori informazioni: ex-vi.sourceforge.net/ex.html
Jimmy MG Lim

3

Se stai lavorando con un file anziché con uno stream, puoi utilizzare l'editor di testo standard ed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

Questo dovrebbe essere disponibile su qualsiasi * nix. La virgola in ',s/a/b/g'dice eddi funzionare su ogni riga (puoi anche usare %, che sarà più familiare se sei abituato a vim), e il resto è una ricerca standard e sostituisci. wgli dice di scrivere (salvare) il file, gli qdice di uscire.

Si noti che, a differenza -idell'opzione sed (e opzioni simili in altri strumenti), in realtà questo modifica il file sul posto anziché barare con i file temporanei.

Non penso che sia possibile farlo funzionare con gli stream, ma poi non ne so davvero molto ede non sarei sorpreso se avesse effettivamente quella capacità (la filosofia unix è quella che è).


2

Usando il comando ancestor (in cui -ssignifica quiet (silent) e la virgola prima dei comandi significa eseguire su tutte le righe):

Basta stampare su STDOUT :

ed -s file <<!
,s/a/b/g
,p
q
!

sostituzione sul posto:

ed -s file <<!
,s/a/b/g
w
q
!
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.