Ingresso:
1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4
Uscita prevista:
1
2
3
4
Quindi, ho bisogno di avere solo il 1 °, 5 °, 9 °, 13 ° valore del file nel file di output. Come fare questo?
Ingresso:
1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4
Uscita prevista:
1
2
3
4
Quindi, ho bisogno di avere solo il 1 °, 5 °, 9 °, 13 ° valore del file nel file di output. Come fare questo?
Risposte:
Utilizzando AWK:
awk '!((NR - 1) % 4)' input > output
Capire come funziona è lasciato come esercizio per il lettore.
NR % 4 == 1
sarebbe IMO più leggibile.
Utilizzando split
(GNU coreutils):
split -nr/1/4 input > output
-n
generare CHUNKS
file di outpute CHUNKS
come
r/K/N
usa la distribuzione round robin e invia Kth of N solo allo stdout senza dividere linee / recordCon GNU sed
:
sed '1~4!d' < input > output
Con standard sed
:
sed -n 'p;n;n;n' < input > output
Con 1
e 4
in $n
e $i
variabili:
sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'
Versione Python, solo per divertimento:
with open('input.txt') as f:
for i, line in enumerate(f.readlines()):
if i%4 == 0:
print(line.strip())
enumerate(f)
dovrebbe essere in grado di fare il lavoro consumando meno memoria
readlines
(da cui deriva l'assorbimento dell'intero file in memoria), puoi usare f.readlines()[::4]
per ottenere ogni quarta riga. Quindi puoi usare print(''.join(f.readlines()[::4]))
.
POSIX sed
: questo metodo utilizza posix sed e quindi può essere eseguito ovunque, o almeno quelle sed che rispettano posix.
$ sed -ne '
/\n/!{
H;s/.*//;x
}
:loop
$bdone
N;s/\n/&/4
tdone
bloop
:done
s/.//;P
' input.file
Un altro è una generazione di codice sed programmatica a fini di scalabilità:
$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file
Perl
: riempiamo l'array A fino a quando non è di 4 dimensioni. Quindi stampiamo il suo primo elemento e cancelliamo anche l'array.
$ perl -pe '
$A[@A] = @A ? <> : $_ while @A < 4;
$_ = (splice @A)[0];
' input.file
Chiama con scriptname filename skip
(4 nel tuo caso) Funziona tirando le iter
linee dalla cima del file e poi solo emettendo l'ultimo. Quindi aumenta iter
di skips
e si ripete finché il valore di iter
non ha superato lines
in file
.
#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
head "$file" -n $iter | tail -n 1
iter=$(( $iter + $skips ))
done
Pure Bash:
mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done
mapfile è un builtin aggiunto in Bash 4 che legge l'input standard in un array, qui chiamato lines
, con una riga per voce. L' -t
opzione rimuove le ultime righe finali.
Se si desidera stampare ogni quarta riga a partire dalla riga 4, è possibile farlo in un comando utilizzando mapfile
l'opzione di callback -C
, che esegue il codice fornito ogni tante righe, con l'intervallo indicato da -c
. L'indice di array corrente e la riga successiva da assegnare vengono dati al codice come argomenti.
mapfile -t -c4 -C 'printf "%.0s%s\n"' < input
Questo utilizza l' printf
integrato; il codice di formato %.0s
sopprime il primo argomento (l'indice), quindi viene stampata solo la riga.
Potresti usare lo stesso comando per stampare ogni quarta riga a partire dalla riga 1, 2 o 3, ma dovresti anteporre 3, 2 o 1 righe input
prima di alimentarlo mapfile
, che penso sia più un problema di quanto valga la pena .
Questo funziona anche:
mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"
Qui, printf
consuma quattro voci dell'array lines
alla volta, stampando solo la prima e saltando le altre tre %.0s
. Non mi piace poiché devi manipolare manualmente la stringa di formato per intervalli o punti di partenza diversi.
sed -n '1~4p'