J'ai un file avec une list de lignes que je veux lire à partir d'un autre file. Je veux sortir ces lignes à un utilitaire ( grep
) qui me laisse lire toute la ligne et en tirer des informations. Le file avec les lignes ressemble à ceci:
cat input.txt 2088 2089 2095 2096
Pour une raison quelconque, je suis coincé là-dessus. Je sais que sed
peut prendre un numéro de ligne spécifique comme argument, mais je n'arrive pas à comprendre comment l'intégrer dans une variable pour l'alimenter.
Si je comprends bien votre problème, quelque chose comme ça devrait fonctionner:
for i in $(cat numbers.txt); do cat lines.txt|tail -n +$i|head -n 1; done
Pour chacun des numéros du file "numbers.txt", il extrait la ligne correspondante de l'autre file et l'imprime.
La même chose avec sed
et xargs
ressemble à ceci:
xargs -i sed "{}q;d" lines.txt <numbers.txt
En supposant que l'interprétation de michas est correcte, voici une solution awk
:
awk 'FNR==NR{a[i++]=$0} # Process the first file FNR!=NR{ # Process the second file for (i in a){ if(FNR==a[i]){ print $0 } } }' file_with_line_numbers other_file
En Perl:
perl -E ' while(<>){ chomp; if($file2) { say if exists $lines{$.} } else { $lines{$_}++ } } continue { if (eof){$.=0; $file2++} }'\ file_with_line_numbers other_file
awk 'NR==FNR{linesToPrint[$0];next} FNR in linesToPrint' line-numbers.txt file.txt
Combine sed
avec xargs
et printf
:
sed -n $(xargs printf "%sp;" < input.txt) data
-n
indique à sed
ne pas imprimer de lignes sauf si vous le dites explicitement. xargs
exécute une command avec les lignes de l'input standard comme arguments. printf
mettra en forme chaque argument comme décrit. Le $(...)
ci-dessus s'étend à (pour votre file d'exemple):
2088p;2089p;2095p;2096p;
qui est une séquence de commands sed
lui disant d'imprimer les lignes 2088, 2089, 2095 et 2096.
De cette façon, vous lisez chaque file une fois, plutôt que plusieurs fois pour xargs -i sed "{}q"
ou xargs -i sed "{}q"
piped head
and tail
.
Une autre solution perl
:
$ perl -MList::Util=any -nle ' BEGIN { open $fh, "<", "input.txt"; @lines = <$fh>; close $fh; } print if any { $_ == $. } @lines; ' file
sed '/[^0-9]/d;s/.$/&p/' <input.txt | sed -nf - file
C'est deux sed
s qui travaillent set. Le premier fait une petite tentative pour s'assurer qu'il ne modifie que les lignes appropriées en refusant d'imprimer toute ligne contenant un seul caractère non numérique et en éditant uniquement les lignes contenant au less un caractère. Fondamentalement, son travail, cependant, est juste de transformer votre list de numéros de ligne en:
2088p 2089p 2095p 2096p
Le second lit son script de command à partir de l'input standard et n'imprime pas les lignes par défaut, de sorte que toutes les lignes éditées par sed
deviennent des lists de commands pour sed
le second. Il exécute ces commands dans le file
.
Apparemment, une technique similaire a déjà été recommandée, mais il existe une différence fondamentale entre les arguments d'invocation d'un process et les inputs. Il existe des limites distinctes sur les lists d'arguments comme:
some_process $(seq a billion)
Ce genre de chose est vouée à l'échec, mais, tant que le process sait comment le gérer, son apport est théoriquement illimité. Dans ce cas, sed
lit un file – le |pipe
– en input et le traite comme un script sed
, ce qui est bien différent de lui donner une string de même longueur sur sa command line lors de l'invocation.