Come commentare più righe corrispondenti a un regex usando sed o awk


3

Ho un file che contiene questo:

[...]

location /static {
    ...
    multiple lines
    ...
}

[...]

location /static/ {
    ...
    multiple lines
    ...
}

[...]

E voglio ottenere:

[...]

# location /static {
#     ...
#     multiple lines
#     ...
# }

[...]

# location /static/ {
#     ...
#     multiple lines
#     ...
# }

[...]

Come posso riuscire a farlo dando il mio file a un comando unix?


Domanda interessante. Ti avrei fatto +1.
James T Snell,

Non conosco la sintassi di Unix, ma potresti provare ad abbinare il modello ^([^\[])e sostituirlo con #\1. Questo funzionerà se nessuna delle linee tra le espressioni tra parentesi ha [a all'inizio della riga.
Eccellente il

Le righe multiple possono contenere }prima della chiusura }?
terdon,

Avrei detto di no ma mi piace che la tua risposta lo assuma alla fine.
Natim

Risposte:


2

Questo non è banale. Se puoi presumere che ogni {}blocco non contenga altri {}blocchi nidificati , è più facile e puoi fare qualcosa del genere:

perl -pe 'if(/location\s*\/static/){$n=1}elsif(/}/){$n=0} s/^/#/ if $n==1;' file

Questa imposta semplicemente $na 1se la linea corrente corrisponde location /statice imposta di nuovo al 0al primo }trovato dopo il location/static. Quindi, purché $n==1, aggiunga #a all'inizio della riga. Il -pflag fa sì che perl esegua automaticamente il ciclo del file di input e stampi ogni riga.

Ora, se puoi avere blocchi annidati di profondità arbitraria all'interno dei blocchi che vuoi commentare, le cose diventano più complicate. Ad esempio, se hai qualcosa del genere:

location /static {
   if(foo){
      print "one";
   }
   elsif(bar){
      print "two";
   }
}

Per casi del genere, la semplice soluzione sopra non funzionerà e dovrai usarne una che tenga traccia del numero di open {. Ad esempio (questo è in realtà un one-liner, puoi copiare / incollare direttamente nel tuo terminale, l'ho appena espanso per chiarezza):

perl -pe 'if(/location\s*\/static/){$n=1;}
          elsif(/}/ && $open==0){$n=0} 
          if($n==1 && /{/){$open++} ## count open brackets
          elsif($n==1 && /}/){$open--} ## count closing brackets
          if($n==1 && $open>0){ s/^/#/}; ' file

Infine, se le soluzioni funzionano come previsto, è possibile aggiungere il -iflag e apportare le modifiche al file stesso:

perl -i -pe 'if(/location\s*\/static/){$n=1}elsif(/}/){$n=0} s/^/#/ if $n==1;' file

Il primo dimentica di commentare l'ultima} riga.
Natim,

Qualcosa del genere? perl -pe 'if(/\s*location\s*\/static/){$n=1}elsif(/\s*}/ && $n==1){$n=0} if($n!=2){s/^/# /} if($n==0){ $n=2}' file
Natim

E per commentare:perl -i -pe 'if(/^# \s*location\s*\/static/){$n=1} elsif(/^# \s*}/ && $n==1){$n=0} if($n!=2){s/^# //} if($n==0){$n=2}' filename
Natim

0

L'estrazione di blocchi delimitati (possibilmente nidificati) con espressioni regolari non è particolarmente divertente o facile. Esiste una soluzione elegante, tuttavia, utilizzando un modulo che è stato spedito con Perl ormai da molto tempo (dal momento che Perl era uno dei tuoi tag), vale a dire. Testo :: Equilibrato :

#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw( extract_bracketed );

my $in = do { local $/ = undef; <> };
while( $in ) {
    my $out;
    if    ( $in =~ s/^(location\s+\S+\s+)// ) { ( $out = $1 . extract_bracketed($in) ) =~ s/^/# /mg }
    elsif ( $in =~ s/^(.*[\r\n]*)// )         { $out = $1 }
    print $out;
}

Questo script funziona consumando (estraendo) e analizzando ripetutamente la parte iniziale della stringa, fino a quando non rimane nulla:

  • Se la parte iniziale contiene la locationparola chiave, seguita da spazio bianco ( \s+) e qualcosa che sembra potrebbe essere un identificatore (attualmente identificato molto rozzamente da una sequenza di caratteri non di spazio bianco \S+), extract_bracketedestrarrà il blocco delimitato che segue (per impostazione predefinita, verrà estratto un blocco delimitato da una qualsiasi delle seguenti coppie: [], {}, ()o <>). extract_bracketedgestirà correttamente i delimitatori nidificati ed equilibrati all'interno del blocco da estrarre. La seguente sostituzione s/^/# /mgè responsabile del commento delle singole righe nel blocco, indipendentemente da quante righe potrebbe contenere. Il blocco (insieme alla parola chiave della posizione principale) viene quindi stampato.

  • Altrimenti, una riga (fino al carattere di nuova riga incluso) viene estratta e stampata non modificata.

Alcune altre cose da notare:

  1. il testo viene letto e memorizzato nella sua interezza in una stringa ( $in) definendo il separatore di record$/
  2. $1è la variabile speciale che contiene il contenuto dell'espressione regolare delimitata da parentesi; ad esempio, per (location\s+\S+\s+)$ 1 contiene il testo location /static(incluso lo spazio finale).
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.