Risposte:
Prova ed
invece:
ed <<< $'1d\nwq' large_file
Se quel "grande" significa circa 10 milioni di linee o più, un uso migliore tail
. Non è in grado di eseguire modifiche sul posto, ma le sue prestazioni rendono la mancanza perdonabile:
tail -n +2 large_file > large_file.new
Modifica per mostrare alcune differenze temporali:
( awk
codice di Jaypal aggiunto per avere tempi di esecuzione sulla stessa macchina (CPU 2.2GHz).)
bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped
bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s
bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s
bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s
bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s
bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s
awk
e ho ottenuto il seguente risultato -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
awk
le prestazioni fossero più vicine a quelle sed
. (Nota per me: non aspettarti mai - prova invece.)
tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;
sto usando un singolo file con un lucchetto per tenere traccia di un unico elenco di attività utilizzato da più processi. Ho iniziato con quello che il manifesto iniziale utilizzato: sed -i 1d large_file
. Ciò causava il blocco del file per 1-2 secondi. La tail/mv
combo si completa quasi istantaneamente. Grazie!
Non è possibile rimuovere in modo efficiente le cose dall'inizio di un file. La rimozione dei dati dall'inizio richiede la riscrittura dell'intero file.
Il troncamento dalla fine di un file può essere molto rapido (il sistema operativo deve solo modificare le informazioni sulla dimensione del file, eventualmente eliminando i blocchi ora inutilizzati). Questo non è generalmente possibile quando si tenta di rimuovere dalla testa di un file.
Teoricamente potrebbe essere "veloce" se si rimuovesse esattamente un intero blocco / estensione, ma non ci sono chiamate di sistema per questo, quindi dovresti fare affidamento sulla semantica specifica del filesystem (se esiste). (O avendo una qualche forma di offset all'interno del primo blocco / estensione per contrassegnare il vero inizio del file, immagino. Nemmeno mai sentito parlare di questo.)
Il metodo più efficiente, non farlo! Se lo fai, in ogni caso, hai bisogno del doppio dello spazio "grande" sul disco e sprechi IO.
Se sei bloccato con un file di grandi dimensioni che desideri leggere senza la 1a riga, attendi di doverlo leggere per rimuovere la 1a riga. Se devi inviare il file da stdin a un programma, usa tail per farlo:
tail -n +2 | your_program
Quando è necessario leggere il file, è possibile cogliere l'occasione per rimuovere la prima riga, ma solo se si dispone dello spazio necessario sul disco:
tail -n +2 | tee large_file2 | your_program
Se non riesci a leggere dallo stdin, usa un fifo:
mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line
ancora meglio se stai usando bash, approfitta della sostituzione del processo:
your_program -i <(tail -n +2 large_file)
Se hai bisogno di cercare nel file, non vedo una soluzione migliore di non rimanere bloccato con il file in primo luogo. Se questo file è stato generato da stdout:
large_file_generator | tail -n +2 > large_file
Altrimenti, esiste sempre la soluzione sostitutiva del processo o del Fifo:
mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file
large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)
Puoi usare Vim in modalità Ex:
ex -sc '1d|x' large_file
1
seleziona la prima riga
d
Elimina
x
salva e chiudi
Questo è solo teorizzare, ma ...
Un filesystem personalizzato (implementato usando FUSE o un meccanismo simile) potrebbe esporre una directory il cui contenuto è esattamente uguale a una directory già esistente altrove, ma con i file troncati come desideri. Il filesystem tradurrebbe tutti gli offset dei file. Quindi non dovresti fare una lunga riscrittura di un file.
Ma dato che questa idea è molto banale, a meno che tu non abbia decine di terabyte di tali file, implementare tale filesystem sarebbe troppo costoso / richiede tempo per essere pratico.
tail
, avrei preferito contare il tempo di fare entrambe rimuovere la prima linea e sostituirlobigfile.txt
conbigfile.new
.