Come cancello le prime n righe e l'ultima riga di un file usando i comandi shell?


31

Ho un file chiamato Element_querycontenente il risultato di una query:

SQL> select count (*) from element;

[Output of the query which I want to keep in my file]

SQL> spool off;

Voglio eliminare la prima e l'ultima riga usando il comando shell.


2
Probabilmente è meglio risolverlo all'interno di SQL * Plus; piuttosto che generare un file e quindi provare a tagliare le cose che non vuoi, puoi semplicemente dire a SQL * Plus di non generare quelle cose per cominciare. Un approccio è descritto nella sezione "Creazione di un file flat" all'indirizzo docs.oracle.com/cd/A84870_01/doc/sqlplus.816/a75664/ch44.htm ; un altro approccio è descritto su stackoverflow.com/q/2299375/978917 .
Ruakh,

Risposte:


48

Usando GNU sed:

sed -i '1d;$d' Element_query

Come funziona :

  • -iopzione modifica il file stesso. È inoltre possibile rimuovere tale opzione e reindirizzare l'output su un nuovo file o un altro comando, se lo si desidera.
  • 1delimina la prima riga ( 1per agire solo sulla prima riga, dper eliminarla)
  • $delimina l'ultima riga ( $per agire solo sull'ultima riga, dper eliminarla)

Andare avanti :

  • Puoi anche eliminare un intervallo. Ad esempio, 1,5deliminerebbe le prime 5 righe.
  • Puoi anche eliminare ogni riga che inizia con l' SQL>uso dell'istruzione/^SQL> /d
  • È possibile eliminare ogni riga vuota con /^$/d
  • Infine, puoi combinare qualsiasi istruzione separandoli con un punto e virgola ( statement1;statement2;satement3;...) o specificandoli separatamente sulla riga di comando ( -e 'statement1' -e 'statement 2' ...)

Se è la sua terza riga da eliminare ... allora devo usare 3d al posto di 1d? se la sua terza riga dall'ultima a cancellare ... allora quale sarà il comando?
pmaipmui,

Come eliminare la terza riga dall'ultima usando i comandi della shell?
pmaipmui,

@Nainita Puoi specificare un intervallo ( 1,3deliminerà le prime tre righe) ma alla fine è un po 'più difficile. A seconda di ciò che desideri, potresti essere meglio usando questo: sed -i '/^SQL> /d' Element_queryper eliminare le righe che iniziano SQL> indipendentemente da dove si trova nel file.
user43791

@Nainita - vedi la mia risposta qui per conteggi di coda arbitrari - offre due soluzioni per eliminare le linee di conteggio rispetto alla fine del file. Uno è un sedone-liner - che funzionerà per eliminare conteggi di riga arbitrari dalla testa e dalla coda di un file, meglio però, fintanto che l'input è un file normale, è solo per raggruppare un singolo input tra due headprocessi - è il il modo più veloce per farlo di solito.
Mikeserv,

Ero solito sed -i '1d' table-backup.sqleliminare la prima riga del file di testo sql
David Thomas il

8

testa; testa

{   head -n[num] >/dev/null
    head -n[num]
}  <infile >outfile

Con quanto sopra è possibile specificare il primo numero di righe da rimuovere dalla testa dell'output con il primo headcomando e il numero di righe su cui scrivere outfilecon il secondo. In genere lo farà anche più velocemente di sed- specialmente quando l'input è grande - nonostante richiedano due invocazioni. Dove sedsicuramente dovrebbe essere preferito, tuttavia, è che non si<infile tratta di un file normale e ricercabile , perché in genere non funzionerà come previsto in quel caso, ma può gestire tutte le modifiche di output in un singolo processo con script.sed

Con una GNU headpuoi usare anche il -modulo negativo [num]nel secondo comando. Nel qual caso il seguente comando eliminerà la prima e l'ultima riga dall'input:

{   head -n1 >/dev/null
    head -n-1
}  <infile >outfile

O con POSIX sed:

Supponiamo, ad esempio, che stavo leggendo un input di 20 righe e che volessi rimuovere il primo 3 e l'ultimo 7. Se avessi deciso di farlo w / sed, lo avrei fatto con un buffer di coda. Prima aggiungerei tre e sette per un conteggio totale delle strisce di dieci e poi farei:

seq 20 | sed -ne:n -e '3d;N;1,10bn' -eP\;D

Questo è un esempio che rimuove le prime 3 e le ultime 7 righe dall'input. L'idea è che è possibile eseguire il buffer di tutte le righe che si desidera rimuovere dalla coda dell'input nello spazio del motivo su una pila, ma Pstampare il primo di questi solo per ogni riga inserita.

  • Sulle righe 1,10 sed Pnon stampa nulla perché per ognuna di esse è impilare l'input nello spazio del modello riga per riga in un bciclo ranch.
  • Sulla terza riga sedviene deliminato tutto lo stack - e quindi le prime 3 righe vengono eliminate dall'output in un colpo solo.
  • Quando sedraggiunge l' $ultima riga di input e tenta di inserire l'estensione N, colpisce EOF e interrompe l'elaborazione completamente. Ma a quel tempo lo spazio del modello contiene tutte le linee 14,20- nessuna delle quali è stata ancora Psfilacciata e mai lo è.
  • Su ogni altra linea si sed Plimita solo fino alla prima \newline che si verifica nello spazio del modello ed Delimina la stessa prima di iniziare un nuovo ciclo con ciò che rimane - o le successive 6 linee di input. La settima riga viene nuovamente aggiunta allo stack con il Ncomando ext nel nuovo ciclo.

E così, seqdell'output (che è di 20 righe numerate in sequenza) , sedstampa solo:

4
5
6
7
8
9
10
11
12
13

Ciò diventa problematico quando il numero di righe che si desidera eliminare dalla coda dell'input è elevato, poiché sedle prestazioni sono direttamente proporzionali alla dimensione del suo spazio del modello. Tuttavia, in molti casi è una soluzione praticabile - e POSIX specifica uno sedspazio modello per gestire almeno 4kb prima del busting.


1
gnu tailsupporta anche la tail -n+<num>sintassi estesa che significa "inizia dalla linea <num>"
UloPe

4

Non ho intenzione di rispondere a come eliminare un numero di righe. Ho intenzione di attaccare il problema in questo modo:

grep -v '#SQL>' Element_query >outfile

Invece di contare le righe, elimina i comandi SQL riconoscendo i prompt. Questa soluzione può quindi essere generalizzata per altri file di output di sessioni SQL con più comandi di soli due.


Mi piace. Non so molto su SQL - ma non c'è alcuna possibilità che i prompt si verifichino in testa alle sue linee di output altrimenti?
Mikeserv,

4

edè "l'editor di testo standard" e dovrebbe essere disponibile su sistemi che non dispongono di GNU sed. È stato originariamente progettato come un editor di testo, ma è adatto allo scripting.

printf '%s\n' 1d '$d' w q | ed Element_query

1delimina la prima riga del file, $d(citato in modo che la shell non pensi che sia una variabile) elimina l'ultima riga, wscrive il file ed qesce ed. printfè qui usato per formattare i comandi per ed- ognuno deve essere seguito da una nuova riga; ci sono ovviamente altri modi per farlo.


3

Esistono diversi modi per rimuovere le righe iniziali e finali da un file.

Puoi utilizzarlo awkpoiché gestisce sia la corrispondenza dei motivi che il conteggio delle righe,

#you need to know length to skip last line, assume we have 100 lines
awk 'NR>1 && NR<100 {print $0};' < inputfile
#or
awk '/SQL/ {next}; {print $0;};' < inputfile |awk 'NR>1&& NR<10 {print $0};'

Puoi utilizzare grep -vper escludere le linee che non desideri per motivo e puoi abbinare più motivi usando l' -Eopzione,

grep -v -E "SQL>" < inputfile > outputfile

Puoi usare heade tailper tagliare conteggi specifici di linee,

lines=$((`wc -l < inputfile`-2)) #how many lines in file, less 2
head -n-1 < inputfile | head -n$lines > outputfile
#or
tail -n+2 < inputfile | head -n$lines > outputfile

È possibile utilizzare vi/vimed eliminare la prima e l'ultima riga (e),

vi inputfile
:1
dd
:$
dd
:w! outputfile
:x

potresti usare uno script perl, saltare la prima riga, salvare ogni riga, stampare quando ottieni una riga successiva,

#left as exercise for the reader :-)

1
Per la heads in realtà non hai bisogno della pipa, e in effetti è meglio non usarla affatto se riesci a cavartela. Quando lo fai head | head, mentre i due processi possono essere eseguiti contemporaneamente, entrambi elaborano praticamente tutti gli stessi dati in modo ridondante. Se lo fai invece { head >dump; head >save; } <insalti solo per offset: il primo legge 10 righe >dumpe il secondo legge le 10 righe successive>save .
Mikeserv,

3

Saresti servito molto meglio tagliando i comandi SQL. Puoi farlo in due modi:

  1. Se sei assolutamente sicuro che la sequenza " SQL>" non si verifica in nessun altro punto dell'output,

    grep -v -F 'SQL> ' < infile > outfile
  2. Se non sei così sicuro,

    grep -v '^SQL> .*;$' < infile > outfile

La seconda versione è più lenta ma più precisa: ignorerà le linee che iniziano esattamente con "SQL>" e terminano con un punto e virgola, che sembrano descrivere le linee che vuoi eliminare.

Tuttavia, sarebbe meglio non inserire l'output aggiuntivo nel file per cominciare. La maggior parte dei sistemi SQL ha un modo per farlo. Non sono troppo esperto di Oracle, ma forse questa risposta potrebbe essere utile.


3

Puoi selezionare le linee tra un intervallo awk(questo presuppone che tu sappia quante linee ci sono):

awk 'NR>1 && NR < 3' file

O in Perl:

perl -ne 'print if $.>1 && $.<3' file

Se non sai quante linee ci sono, puoi calcolarle al volo usando grep(nota che questo non conterà le linee vuote, usa anche grep -c '' fileper contarle):

awk -vm="$(grep -c . file2.txt)" 'NR>1 && NR<m' file2.txt

3

Prova questa soluzione:

tail -n +2 name_of_file | head -n-1

Personalizzazione

Puoi facilmente adattarlo per eliminare le n prime righe cambiando il +2di tail;
o per eliminare le ultime n righe modificando -1di head.


Questa soluzione non è corretta poiché stampa la prima riga.
xhienne

1
@xhienne Siamo spiacenti, è stato un errore. Ho scritto 1 invece di 2 come parametro di "coda". Ora funziona, grazie! :)
Gabrer

1

Utilizzando awk:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfile: Reindirizza il contenuto di inputfileper awks'stdin
  • > outputfile: Reindirizza il contenuto di awk's stdoutperoutputfile
  • NR>1: esegue le seguenti azioni solo se il numero del record in elaborazione è maggiore di 1
  • {print r}: stampa il contenuto della variabile r
  • {r=$0}: assegna il contenuto del record in elaborazione alla variabile r

Quindi alla prima esecuzione dello awkscript, il primo blocco di azioni non viene eseguito, mentre il secondo blocco di azioni viene eseguito e il contenuto del record viene assegnato alla variabile r; alla seconda esecuzione, viene eseguito il primo blocco di azioni e rviene stampato il contenuto della variabile (quindi viene stampato il record precedente); questo ha l'effetto di stampare ogni riga elaborata ma la prima e l'ultima.


Non stai escludendo la prima riga. Con NR == 2, si stampa la prima riga di input in cui è stata memorizzata r.
Xhienne
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.