it-swarm-eu.dev

Come posso estrarre un intervallo di linee prestabilito da un file di testo su Unix?

Dispongo di un dump SQL di ~ 23000 righe contenente diversi database di dati. Ho bisogno di estrarre una certa sezione di questo file (cioè i dati per un singolo database) e metterlo in un nuovo file. Conosco i numeri di inizio e di fine riga dei dati che voglio.

Qualcuno conosce un comando Unix (o una serie di comandi) per estrarre tutte le linee da un file tra le linee 16224 e 16482 e poi reindirizzare in un nuovo file?

447
Adam J. Forster
sed -n '16224,16482p;16483q' filename > newfile

Dal manuale sed :

p - Stampa lo spazio pattern (sullo standard output). Questo comando viene solitamente utilizzato solo in combinazione con l'opzione -n ​​della riga di comando.

n - Se la stampa automatica non è disabilitata, stampare lo spazio del motivo, quindi, a prescindere, sostituire lo spazio del motivo con la riga successiva di immissione. Se non c'è più input quindi sed uscite senza elaborazione più comandi.

q - Esci sed senza elaborare ulteriori comandi o input . Si noti che lo spazio modello attuale viene stampato se la stampa automatica non è disabilitata con l'opzione -n.

e

Gli indirizzi in uno script sed possono essere in una delle seguenti forme:

numero La specifica di un numero di riga corrisponde solo a quella linea nell'input.

È possibile specificare un intervallo di indirizzi specificando due indirizzi separato da una virgola (,). Un intervallo di indirizzi combacia con le righe a partire da dove il primo indirizzo corrisponde e continua fino al secondo corrispondenze di indirizzo (incluso).

681
boxxar
sed -n '16224,16482 p' orig-data-file > new-file

Dove 16224,16482 sono il numero di riga iniziale e il numero di fine riga, inclusi. Questo è 1-indicizzato. -n sopprime l'eco dell'ingresso come output, che chiaramente non vuoi; i numeri indicano l'intervallo di linee su cui operare il seguente comando; il comando p stampa le righe pertinenti.

195
JXG

Abbastanza semplice con testa/coda:

head -16482 in.sql | tail -258 > out.sql

usando sed:

sed -n '16482,16482p' in.sql > out.sql

usando awk:

awk 'NR>=10&&NR<=20' in.sql > out.sql
78
manveru

Potresti usare 'vi' e poi il seguente comando:

:16224,16482w!/tmp/some-file

In alternativa: 

cat file | head -n 16482 | tail -n 258

EDIT: - Solo per aggiungere una spiegazione, si usa head -n 16482 per visualizzare le prime 16482 linee, quindi usare tail -n 258 per ottenere le ultime 258 righe dalla prima uscita. 

25
Mark Janssen

C'è un altro approccio con awk:

awk 'NR==16224, NR==16482' file

Se il file è enorme, può essere buono per exit dopo aver letto l'ultima riga desiderata. In questo modo non leggerà il file inutilmente fino alla fine:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
20
fedorqui
Perl -ne 'print if 16224..16482' file.txt > new_file.txt
14
mmaibaum
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2
8
Cetra

sed -n '16224,16482p' < dump.sql

5
cubex
cat dump.txt | head -16224 | tail -258

dovrebbe fare il trucco Lo svantaggio di questo approccio è che è necessario fare l'aritmetica per determinare l'argomento per la coda e per spiegare se si desidera che il 'tra' per includere la linea finale o meno.

5
JP Lodine

Veloce e sporco:

head -16428 < file.in | tail -259 > file.out

Probabilmente non è il modo migliore per farlo, ma dovrebbe funzionare.

BTW: 259 = 16482-16224 + 1.

3
jan.vdbergh

Stavo per pubblicare il trucco testa/coda, ma in realtà probabilmente avrei acceso solo emacs. ;-)

  1. esc-x goto-line ret 16224
  2. marchio (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

apri il nuovo file di output, ctl-y save

Vediamo cosa sta succedendo.

3
sammyo

Anche noi possiamo farlo per controllare a linea di comando:

cat filename|sed 'n1,n2!d' > abc.txt

Per esempio:

cat foo.pl|sed '100,200!d' > abc.txt
2
Chinmoy Padhi

Utilizzando Ruby:

Ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
2
Carl Blakeley

Io userei:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR contiene il numero di record (linea) della riga da leggere dal file.

2
Paddy3118

Ho scritto un programma Haskell chiamato splitter che fa esattamente questo: avere un leggere il mio post sul blog di rilascio .

È possibile utilizzare il programma come segue:

$ cat somefile | splitter 16224-16482

E questo è tutto ciò che c'è da fare. Avrai bisogno di Haskell per installarlo. Appena:

$ cabal install splitter

E hai finito. Spero che trovi utile questo programma.

2
Robert Massaioli

Questo potrebbe funzionare per te (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

o approfittando di bash:

sed -n $'16224,16482w newfile\n16482q' file
1
potong

Ho scritto un piccolo script bash che è possibile eseguire dalla riga di comando, a condizione che si aggiorni il PATH per includere la sua directory (oppure si può inserirlo in una directory che è già contenuta nel PATH).

Utilizzo: $ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0
1
Nerdfighter

Volevo fare la stessa cosa da uno script usando una variabile e l'ho raggiunto mettendo virgolette attorno alla variabile $ per separare il nome della variabile dalla p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

Volevo dividere un elenco in cartelle separate e ho trovato la domanda iniziale e ho risposto a un passaggio utile. (comando split non un'opzione sul vecchio sistema operativo ho il codice porta su).

1
KevinY

Dato che stiamo parlando di estrarre linee di testo da un file di testo, darò un caso particolare in cui si desidera estrarre tutte le linee che corrispondono a un determinato modello. 

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Stamperà la riga [Dati] e il resto. Se vuoi il testo da line1 al pattern, digiti: sed -n '1,/Data/p' myfile. Inoltre, se conosci due pattern (meglio essere unici nel tuo testo), sia la riga iniziale che quella finale dell'intervallo possono essere specificate con le corrispondenze.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile
0
Kemin Zhou

In piedi sulle spalle di boxxar, mi piace questo:

sed -n '<first line>,$p;<last line>q' input

per esempio.

sed -n '16224,$p;16482q' input

$ significa "ultima riga", quindi il primo comando rende sed stampa tutte le righe che iniziano con la riga 16224 e il secondo comando rende sed quit after printing line 16428. (L'aggiunta di 1 per l'intervallo q- nella soluzione di boxxar non sembra essere necessaria.)

Mi piace questa variante perché non è necessario specificare il numero della linea di fine due volte. E ho rilevato che l'uso di $ non ha effetti negativi sulle prestazioni.

0
Tilman Vogel

Il -n nelle risposte accetta funziona. Ecco un altro modo nel caso in cui sei inclinato.

cat $filename | sed "${linenum}p;d";

Questo fa quanto segue:

  1. pipe nel contenuto di un file (o inserisci il testo nel modo desiderato).
  2. sed seleziona la linea data, la stampa
  3. d è necessario per eliminare le righe, altrimenti sed assumerà che tutte le linee verranno stampate. Ad esempio, senza la d, otterrete tutte le righe stampate dalla riga selezionata stampate due volte perché avete la parte $ {linoum} p che chiede che venga stampata. Sono abbastanza sicuro che -n stia fondamentalmente facendo la stessa cosa del d qui.
0
ThinkBonobo