GNU/Linux >> Linux Esercitazione >  >> Linux

Guida introduttiva al comando SED [Guida per principianti]

Sed fa parte della cassetta degli attrezzi standard di Unix dalla fine degli anni '60. Come qualsiasi editor di testo, ti aiuterà a modificare i file di testo. Tuttavia, contrariamente agli editor di testo che potresti aver già utilizzato, questo non è interattivo.

Ciò significa che devi specificare in anticipo le trasformazioni che desideri applicare a un file e quindi lo strumento può applicare tali trasformazioni senza supervisione.

La migliore descrizione degli obiettivi di progettazione dello strumento viene da Lee E. McMahon, lo sviluppatore principale dell'implementazione originale nel suo documento originale:

Sed è un editor di contesto non interattivo che viene eseguito sul sistema operativo UNIX. Sed è progettato per essere particolarmente utile in tre casi:

  1. Per modificare file troppo grandi per una comoda modifica interattiva;
  2. Per modificare file di qualsiasi dimensione quando la sequenza dei comandi di modifica è troppo complicata per essere digitata comodamente in modalità interattiva.
  3. Per eseguire più funzioni di editing "globale" in modo efficiente in un passaggio attraverso l'input.

I design degli obiettivi (1) e (3) sono probabilmente meno rilevanti con il nostro hardware moderno, ma il secondo rimane valido. Come aggiunta personale, direi che sed è particolarmente adatto per attività ripetitive come quando si desidera applicare la stessa trasformazione a un insieme di file.

Impara i comandi SED di base con questi esempi

Per darti un assaggio della potenza di sed, prenderò in considerazione il caso di uno sviluppatore che deve aggiungere un'intestazione di licenza sopra ciascuno dei file sorgente nel suo progetto:

[email protected]:~$ head MIT.LICENSE *.sh
==> MIT.LICENSE <==
-----8<----------------------------------------------------------------
Copyright <YEAR> <COPYRIGHT HOLDER>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

==> script1.sh <==
#!/bin/bash

echo Hello, I\'m the first script

==> script2.sh <==
#!/bin/bash

cat << EOF
Hello, I'm the second script
EOF

Non solo vorrei vedere il file di licenza sopra ogni script di shell, ma vorrei anche che l'anno e il segnaposto del copyright fossero sostituiti dal loro valore effettivo. Questo sarà il nostro primo caso d'uso.

Nota:se vuoi esercitarti da solo, puoi scaricare i file di esempio dal mio sito web. Puoi anche dare un'occhiata al video che completa questo articolo:

1. Sostituzione del testo in SED

Nel mio file di licenza, vorrei sostituire i segnaposto e con il loro valore effettivo.

Questo è un lavoro perfettamente adatto per la sostituzione di sed comando. Probabilmente il più utile di tutti i comandi sed:

[email protected]:~$ sed -e 's/<YEAR>/2018/' MIT.LICENSE  | head -5
-----8<----------------------------------------------------------------
Copyright 2018 <COPYRIGHT HOLDER>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

Utilizzando una pipe (| ), ho inoltrato l'output del comando sed al head strumento per visualizzare solo le prime cinque righe qui. Tuttavia, per l'argomento specifico di oggi, la parte più interessante è il s/<YEAR>/2018/ espressione.

Sed funziona elaborando il file di input una riga alla volta. Su ogni riga, il sostituto (s ) sostituirà la prima occorrenza del testo tra le prime due barre (/<YEAR>/ ) dal testo tra gli ultimi due (/2018/ ). Pensalo come la funzione di sostituzione della ricerca che hai in un editor di testo della GUI.

Vale la pena menzionare qui, il file MIT.LICENSE originale non è stato modificato. Ti ho permesso di verificarlo da solo usando il seguente comando:

head -5 MIT.LICENSE

2. Sostituzione del testo... di nuovo

Ottimo:abbiamo sostituito il segnaposto dell'anno. Ma ce n'è un secondo da sostituire. Se hai capito l'esempio precedente, potresti probabilmente immaginare una seconda espressione sed come questa:

's/<COPYRIGHT HOLDER>/Sylvain Leroux/'

Ma dove posizionarlo? Bene, hai diverse scelte. Il più ovvio se hai già familiarità con il concetto di reindirizzamento è reindirizzare l'output del nostro primo comando sed a una seconda istanza di sed:

[email protected]:~$ sed -e 's/<YEAR>/2018/' MIT.LICENSE  |
    sed -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' |
    head -5
----8<----------------------------------------------------------------
Copyright 2018 Sylvain Leroux

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

Ma possiamo fare di meglio. Dal momento che il -e l'opzione introduce un'espressione sed, possiamo usarne diversi come parte della stessa invocazione sed e il risultato sarà lo stesso:

# Pay special attention to the \ at the end of the lines
# specifying the *same* command continues on the
# next line:
sh$ sed -e 's/<YEAR>/2018/'  \
                -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
                MIT.LICENSE |
        head -5

Infine, puoi anche specificare diversi comandi nella stessa espressione sed separandoli con una nuova riga. Ciò è particolarmente utile quando inizi a scrivere programmi sed più complessi:

# Pay special attention to the single-quotes and
# backslash placement:
sh$ sed -e 's/<YEAR>/2018/
            s/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
        MIT.LICENSE |
    head -5

3. Inserimento di testo

Ora abbiamo sostituito i segnaposto con il loro valore effettivo. Ma abbiamo ancora del lavoro da fare prima di poter inserire quel file di licenza nei file di progetto. Quelli che in seguito saranno script di shell, ogni riga della licenza deve iniziare con un octothorp (# ) affinché la shell lo capisca non dovrebbe cercare di interpretare quelle righe.

Per questo, useremo di nuovo il comando di sostituzione. Qualcosa che non ho menzionato in precedenza è, contrariamente alla maggior parte delle funzionalità di sostituzione della ricerca degli editor della GUI, il modello di ricerca non è necessariamente la stringa letterale da cercare. In effetti, questa è un'espressione regolare (regex). Ciò significa che, oltre ai caratteri semplici che corrisponderanno alla lettera, puoi utilizzare caratteri che avranno un significato speciale. Ad esempio, il cursore (^ ) rappresenta l'inizio della riga, il simbolo del dollaro ($ ) la fine della riga o, come ultimo esempio, il punto-stella (.* ) indica qualsiasi sequenza di 0, 1 o più caratteri. Ci sono molti altri metacaratteri simili, ma per ora questo è più che sufficiente.

Quindi per inserire del testo all'inizio di una riga, un'opzione è quella di sostituire l'inizio della riga da quel testo:

[email protected]:~$ sed -e 's/<YEAR>/2018/'  \
        -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
        -e 's/^/# /' \
        MIT.LICENSE | head -5
# -----8<----------------------------------------------------------------
# Copyright 2018 Sylvain Leroux
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

4. Cancellazione delle righe selezionate

Il comando di sostituzione in sed è così versatile che puoi esprimere la maggior parte delle trasformazioni del testo usandolo. Ad esempio, per rimuovere le linee tratteggiate sopra e sotto il testo della licenza, potrei scrivere che:

[email protected]:~$ sed -e 's/<YEAR>/2018/'  \
        -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
        -e 's/^/# /' \
        -e 's/^.*----.*$//' \
        MIT.LICENSE | head -5

# Copyright 2018 Sylvain Leroux
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the

Quella sostituzione successiva ha sostituito con la stringa vuota tutto il testo:

Simbolo Descrizione
^ A partire dall'inizio della riga
.* Seguito da qualsiasi sequenza di 0, 1 o più caratteri
---- Seguito da 4 trattini
.* Seguito da qualsiasi sequenza di 0, 1 o più caratteri
$ Seguito dalla fine della riga

In breve, questo sostituirà l'intera riga con la stringa vuota if contiene quattro trattini di fila. Ma la riga vuota rimane nell'output e apparirà come una riga vuota.

A seconda delle tue esigenze e dei tuoi gusti esatti, potresti anche prendere in considerazione la soluzione alternativa di seguito. Ve lo lascio esaminare in dettaglio per individuare le modifiche nel comando e identificare da soli quali sono state le conseguenze sul risultato:

[email protected]:~$ sed -e 's/<YEAR>/2018/'  \
        -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
        -e 's/^.*----.*$//' \
        -e 's/^/# /' \
        MIT.LICENSE | head -5

Se trovi che l'espressione regolare usata per cancellare la linea sia un po' troppo complessa, potremmo anche trarre vantaggio da un'altra funzione sed. Quasi tutti i comandi possono assumere un indirizzo facoltativo prima del nome del comando. Se presente, limiterà l'ambito del comando alle righe corrispondenti quell'indirizzo:

[email protected]:~$ sed -e 's/<YEAR>/2018/'  \
        -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
        -e 's/^/# /' \
        -e '/----/s/^.*$//' \
        MIT.LICENSE | head -5

Ora l'ultimo comando di sostituzione verrà applicato solo alle righe corrispondenti (cioè "contenenti") quattro trattini di seguito. E per ogni riga corrispondente, sostituirà tutto (.* ) tra l'inizio (^ ) e fine ($ ) della riga dalla stringa vuota (// )

5. Rimozione delle righe selezionate

Nella sezione precedente, abbiamo ottimizzato il comando di sostituzione per cancellare alcune righe di testo. Ma le linee vuote sono rimaste presenti. A volte questo è desiderabile. A volte non lo è. In quest'ultimo caso, potresti voler esaminare l'eliminazione comando per rimuovere intere righe dall'output:

# Below, the redirection '> LICENSE' is used to store
# the result of the sed command into the newly
# created LICENSE file:
[email protected]:~$ sed -e 's/<YEAR>/2018/'  \
        -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
        -e 's/^/# /' \
        -e '/----/d' \
        MIT.LICENSE > LICENSE
[email protected]:~$ head -5 LICENSE
# Copyright 2018 Sylvain Leroux
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including

Il d è l'elimina nome del comando. Proprio come i s era la sostituzione nome del comando. Qui, abbiamo specificato un indirizzo prima del comando in modo che vengano rimosse solo le righe corrispondenti (senza alcun indirizzo, il d comando avrebbe cancellato ogni riga del file)

6. Converti in maiuscolo

Fino ad ora, ci siamo concentrati principalmente sulla parte superiore del file di licenza. Ma in effetti ci sono alcune modifiche che vorrei apportare un po' più avanti nei documenti. Vediamo prima di cosa parlo:

[email protected]:~$ sed -ne '/The above/,$p' LICENSE
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# The software is provided "as is", without warranty of any kind,
# express or implied, including but not limited to the warranties of
# merchantability, fitness for a particular purpose and noninfringement.
# In no event shall the authors or copyright holders be liable for any
# claim, damages or other liability, whether in an action of contract,
# tort or otherwise, arising from, out of or in connection with the
# software or the use or other dealings in the software.

Nel comando precedente, usando l'opzione -n ​​ho disabilitato la stampa automatica dello spazio del modello. Ciò significa che sed non stamperà più nulla sull'output a meno che non glielo chieda esplicitamente. Questo è esattamente quello che faccio usando il comando print (p). Notare invece di utilizzare un singolo indirizzo prima del comando p, ho usato un intervallo per visualizzare il testo tra la riga contenente il testo “The above” e la fine del documento ($).

Il comando print può essere utile quando devi estrarre alcune parti di un file. Tuttavia, per oggi, volevo solo visualizzare gli ultimi due paragrafi per spiegare di cosa ho bisogno ora:come è tradizione con i file di licenza, vorrei coprirmi chiarendo che il software viene fornito "così com'è". Quindi vorrei mettere in risalto l'ultimo paragrafo (che inizia con “Il software”) riscrivendolo tutto in maiuscolo.

Nella parte di sostituzione di un comando di sostituzione, un &viene sostituito dal testo che corrisponde al modello di ricerca. Usando l'estensione \U GNU, possiamo cambiare il caso della stringa sostitutiva:

[email protected]:~$ sed -i -e '/The software/,$s/.*/\U&/' LICENSE
[email protected]:~$ cat LICENSE

In testo normale s/.*/\U&/ significa "sostituisci qualsiasi testo (.* )dal maiuscolo (\U ) versione di se stesso (& ). Ti lascio verificare da solo, l'ultimo paragrafo ora dovrebbe essere scritto tutto in maiuscolo. A proposito, potresti averlo notato a causa di -i flag, le modifiche sono state applicate direttamente al file LICENSE.

Lo vedremo più in dettaglio nella prossima sezione. Nel frattempo, ti lascio esercitarti e modificare quei comandi a tuo piacimento. Una volta che avrai un file di licenza che corrisponde ai tuoi gusti, sarà il momento di vedere come includerlo prima di ogni file sorgente del progetto.

7. Inserimento di un file di testo

Se ti aspetti qualche comando complesso qui, rimarrai deluso:inserire un file in un altro è piuttosto semplice:

sed -i -e '1r LICENSE' script1.sh
cat script1.sh

Due cose da vedere qui:

  1. il r LICENSE expression è il comando da leggere e inserire un file esterno nel file attualmente in elaborazione. Qui è preceduto dal numero 1 che è un indirizzo che corrisponde solo alla riga 1 del file di input.
  2. il -i l'opzione consente di modificare un file in atto . Ciò significa che sed creerà un file temporaneo dietro le quinte per memorizzare lì il suo output e, una volta completata l'elaborazione, sostituirà il file originale con quello modificato.

Un interessante effetto collaterale dell'opzione '-i' è che puoi specificare diversi nomi di file sulla riga di comando e sed applicherà le stesse trasformazioni a ciascuno di essi indipendentemente :

sed -i -e '1r LICENSE' *.sh

8. Ritorno al futuro

Come ultimo esempio di comando sed, immaginiamo che siano passati alcuni anni e ora siamo al 1 gennaio 2024. L'avviso di copyright di tutti i file deve essere aggiornato. Esistono diversi casi d'uso, a seconda di quando sono stati creati i file di progetto. Pertanto, i nostri avvisi sul copyright dovrebbero seguire uno di questi due formati:

Copyright attuale Descrizione
Copyright 2023 Per i file creati l'anno scorso
Copyright 2018-2023 Per i file creati prima dell'anno scorso

Possiamo acquisire questi due casi d'uso contemporaneamente usando un'espressione regolare estesa (-E). Le uniche cose "estese" che useremo davvero qui sono le parentesi:

sed -i -Ee 's/Copyright (....)(-....)?/Copyright \1-2024/' *.sh

Ti incoraggio a modificare manualmente l'avviso di copyright nei file *.sh e quindi eseguire il comando sopra in diversi casi d'uso per vedere come funziona.

Alla fine potrebbe aiutare la tua comprensione se dico, nel modello di ricerca:Copyright::è un testo letterale che corrisponderà alla lettera; (… .)::definisce un gruppo di acquisizione che corrisponde a quattro caratteri arbitrari. Si spera che le quattro cifre di un anno; (-… .)?::definisce un gruppo di acquisizione che corrisponde a un trattino seguito da quattro caratteri arbitrari. Il punto interrogativo alla fine indica che il gruppo è facoltativo. Può essere presente o meno nella riga di input.

Nella stringa di sostituzione:Copyright::è un testo letterale che verrà copiato alla lettera; \1::è il contenuto del primo gruppo di acquisizione -2024::è un testo letterale che verrà copiato alla lettera.

Se ti sei preso il tempo per controllare il comando da solo, dovrebbe confermare se applico quelle regole ai casi d'uso descritti nella tabella precedente, otterrò qualcosa del genere:

\2
Testo corrispondente \1 Stringa sostitutiva
Copyright 2023 2023 Copyright 2023-2024
Copyright 2018-2023 2018 -2023 Copyright 2018-2024

Per concludere la nostra guida SED

Abbiamo solo graffiato la superficie qui. Il sed strumento è molto più potente di quello. Tuttavia, anche se abbiamo visto solo quattro comandi (s , p , d e i ) e alcuni costrutti di espressioni regolari di base (^ , $ , . , ? e .* ), hai già abbastanza conoscenze per risolverne molti problemi quotidiani.

Visto che mi piace concludere un tutorial con una piccola sfida, ecco cosa vi propongo:se avete scaricato il materiale di supporto, troverete nella directory del progetto un file chiamato hello.c . Questo è il file sorgente di un programma C di base:

[email protected]:~$ ls
hello.c  MIT.LICENSE  script1.sh  script2.sh
[email protected]:~$ gcc hello.c -o hello
[email protected]:~$ ./hello sylvain
Hello sylvain
[email protected]:~$ cat hello.c

Ci sono già alcuni commenti nel file di origine. Usandoli come esempi della sintassi dei commenti nel linguaggio di programmazione C, potresti inserire la licenza MIT in hello.c file sorgente usando il comando sed? Puoi usare uno o più comandi sed, puoi reindirizzare l'output di un comando sed in un altro, puoi usare file temporanei se vuoi, ma tu non autorizzato a usare qualsiasi comando diverso da sed. Naturalmente, il file sorgente C dovrebbe ancora essere compilato dopo aver inserito la licenza!

Ora ti lascio pensare a quel piccolo problema e spero che l'articolo e il video di accompagnamento ti siano piaciuti. Se vuoi saperne di più su sed, faccelo sapere utilizzando la sezione commenti!


Linux
  1. Iniziare con Zsh

  2. Iniziare con il comando tac di Linux

  3. Iniziare con il comando cat di Linux

  4. Iniziare con ls

  5. Guida introduttiva a Multipass – Esecuzione di macchine virtuali Ubuntu

Guida introduttiva a Nano Text Editor [Guida per principianti]

Guida introduttiva a Markdown [Guida per principianti]

Guida introduttiva a cPanel/WHM

Guida introduttiva al comando AWK [Guida per principianti]

Guida introduttiva a Tmux [Guida per principianti]

Guida introduttiva al comando Tar