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 == 1sarebbe IMO più leggibile.
Utilizzando split (GNU coreutils):
split -nr/1/4 input > output
-ngenerare CHUNKSfile di outpute CHUNKScome
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 1e 4in $ne $ivariabili:
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 iterlinee dalla cima del file e poi solo emettendo l'ultimo. Quindi aumenta iterdi skipse si ripete finché il valore di iternon ha superato linesin 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' -topzione rimuove le ultime righe finali.
Se si desidera stampare ogni quarta riga a partire dalla riga 4, è possibile farlo in un comando utilizzando mapfilel'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' printfintegrato; il codice di formato %.0ssopprime 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 inputprima 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, printfconsuma quattro voci dell'array linesalla 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'