GNU/Linux >> Linux Esercitazione >  >> Linux

Eliminare stringhe multilinea?

Ci sono state diverse domande qui riguardanti la sostituzione di stringhe multilinea usando la shell Unix, ma non ne ho trovata una che funzioni in questa situazione.

Sto cercando di rimuovere chiavi e vincoli da alcuni DDL MySQL, che assomiglia a questo (un esempio):

CREATE TABLE `access_group` (
  `GROUP_ID` int(10) NOT NULL AUTO_INCREMENT,
  `PARENT_GROUP_ID` int(10) DEFAULT NULL,
  `GROUP_NAME` varchar(45) NOT NULL,
  `GROUP_DESC` varchar(45) NOT NULL DEFAULT '',
  PRIMARY KEY (`GROUP_ID`),
  KEY `testkey` (`PARENT_GROUP_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=latin1;

Voglio rimuovere tutto dalla virgola che termina la riga prima di 'PRIMARY KEY' fino a, ma non includendo ') ENGINE=' (possono esserci zero o più righe tra queste e non inizieranno sempre con KEY o avranno il parentesi, ma ') ENGINE=' è coerente). Il risultato dovrebbe assomigliare a questo:

CREATE TABLE `access_group` (
  `GROUP_ID` int(10) NOT NULL AUTO_INCREMENT,
  `PARENT_GROUP_ID` int(10) DEFAULT NULL,
  `GROUP_NAME` varchar(45) NOT NULL,
  `GROUP_DESC` varchar(45) NOT NULL DEFAULT ''
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=latin1;

Sono disponibile a utilizzare qualsiasi utilità standard della riga di comando (ad es. sed, perl, awk), ma poiché questi file possono essere abbastanza grandi (alcuni sono dell'ordine di decine o centinaia di GB) devono essere efficienti. Dato che i file vengono solitamente archiviati con gzip (o talvolta elaboro l'output dell'utilità di dump di mysql direttamente anziché prima scriverlo su disco), ho bisogno di qualcosa che possa essere inviato e scaricato.

Risposta accettata:

Mantieni lo stato se stampare la riga precedente, modifica detto per rimuovere la virgola quando necessario. Questo metodo mantiene solo una o due righe del file in memoria.

#!/usr/bin/env perl
use strict;
use warnings;

my $printing = 1;
my $previous;

# reads from standard input (optionally with the conventional -) or from
# the named files
shift @ARGV if @ARGV == 1 and $ARGV[0] eq '-';
while ( my $line = readline ) {
    if ( $line =~ m/^\s+PRIMARY KEY/ ) {
        $previous =~ s/,[ \t]*$//;
        $printing = 0;
    } elsif ( $line =~ m/^\) ENGINE/ ) {
        $printing = 1;
    } elsif ( !$printing ) {
        undef $previous;
    }
    print $previous if defined $previous;
    $previous = $line if $printing;
}
# don't forget last line after fall off the end of input (eof)
print $previous if defined $previous;

Linux
  1. Elimina ricorsivamente i file in modo sicuro:distruzione

  2. Opzione Rm per fallire su file inesistenti?

  3. Rimappatura della chiave di accensione da eliminare?

  4. Automatizzare le stringhe di digitazione in Xmacro?

  5. Come concatenare stringhe in Bash

Bash concatena le stringhe

Come confrontare le stringhe in Bash

Come eliminare le righe in Vim / Vi

Come usare bash if -z e if -n per testare le stringhe in Linux

/dev/null in Linux

Installa PowerDNS su Ubuntu 18.04, 20.04 e 22.04