Imaginez une sortie d'une command comme
44444 55555 11111 22222 33333
comment puis-je sortinger les N premières lignes (les deux premières dans l'exemple ci-dessus) et les append à la fin, mais sans utiliser de file temp (donc uniquement en utilisant des pipes)?
11111 22222 33333 44444 55555
Quelque chose comme le | sed -n '3,5p;1,2p'
| sed -n '3,5p;1,2p'
(qui évidemment ne fonctionne pas comme sed ne se soucie pas de l'ordre des commands).
Il suffit de copyr ces lignes dans le tampon de conservation (puis de les supprimer) et, à la dernière ligne, d'append le contenu de la memory tampon d'attente à l'espace de model:
some command | sed '1,NUMBER{ # in this range H # append line to hold space and 1h # overwrite if it's the 1st line d # then delete the line } $G' # on last line append hold buffer content
Avec gnu sed
vous pouvez l'écrire comme
some command | sed '1,NUMBER{H;1h;d;};$G'
Voici un autre moyen avec ol ed
(il affiche la sortie d' some command
dans le tampon de text, puis m
ove les lignes 1,NUMBER
après le la $
t):
ed -s <<IN r ! some command 1,NUMBERm$ ,p q IN
Notez que – comme indiqué – ils échoueront tous les deux si la sortie a less de NUMBER
+1 lignes. Une approche plus solide serait (syntaxe gnu sed
):
some command | sed '1,NUMBER{H;1h;$!d;${g;q;};};$G'
celle-ci ne supprime que les lignes de cette plage tant qu'elles ne sont pas la dernière ligne ( $!d
) – sinon elle écrase l'espace des patterns avec le contenu de la memory tampon ( g
) puis les q
uits.
Une approche awk
:
cmd | awk -vn=3 ' NR <= n {head = head $0 "\n"; next} {print} END {printf "%s", head}'
Un avantage sur l'approche sed
@ don_crissti est qu'il fonctionne toujours (sort les lignes) si la sortie a n
lignes ou less.
J'ai xclip
et avec cela cela peut être fait de cette façon:
./a_command | xclip -in && xclip -o | tail -n +3 && xclip -o | head -n 2
Voici sa description:
xclip - command line interface to X selections (clipboard) NAME xclip - command line interface to X selections (clipboard) SYNOPSIS xclip [OPTION] [FILE]... DESCRIPTION Reads from standard in, or from one or more files, and makes the data available as an X selection for pasting into X applications. Prints current X selection to standard out. -i, -in read text into X selection from standard input or files (default) -o, -out prints the selection to standard out (generally for piping to a file or program)
Une manière Perl:
perl -ne '$.<3?($f.=$_):print;}{print $f'
Ou, la même chose écrite less cryptiquement:
perl -ne 'if($.<3){ $f.=$_ } else{ print } END{print $f}'
Par exemple:
$ cat file 44444 55555 11111 22222 33333 $ cat file | perl -ne '$.<3?($f.=$_):print;}{print $f' 11111 22222 33333 44444 55555
-ne
: lit le file d'input / stream ligne par ligne et applique le script donné par -e
à chaque ligne. $.<3
: $.
est le numéro de ligne actuel, alors changez 3
en nombre de lignes que vous voulez décaler. $.<3?($f.=$_):print;
: c'est l'opérateur conditionnel, le format général est la condition ? case1 : case2
condition ? case1 : case2
, il exécutera case1
si la condition
est true et case2
si elle est fausse. Ici, si le numéro de ligne actuel est inférieur à 3, il ajoute la ligne courante ( $_
) à la variable $f
et, si le numéro de ligne est supérieur à 3, il s'imprime. }{ print $f
: le }{
est un raccourci perl pour END{}
. Il fonctionnera après que toutes les lignes d'input ont été traitées. À ce stade, nous aurons collecté toutes les lignes que nous voulons décaler et nous aurons imprimé tous ceux que nous voulons laisser seuls, alors imprimez les lignes sauvegardées comme $f
. Utilisez POSIX ex
. Oui, il est destiné à l'édition de files, mais il fonctionnera dans un pipeline.
printf %s\\n 111 222 333 444 555 | ex -sc '1,2m$|%p|q!' /dev/stdin
Cela peut avoir des commands arbitraires ajoutées au début ou à la fin du pipeline et fonctionneront de la même façon. Mieux encore, étant donné la présence de /dev/stdin
, il est conforme à POSIX.
(Je ne sais pas si /dev/stdin
est spécifié dans POSIX ou pas, mais je vois qu'il est présent à la fois sous Linux et Mac OS X.)
Cela a un avantage de lisibilité par rapport à l'utilisation de l'espace de sed
de sed
– vous dites juste ex
"déplacer ces lignes jusqu'à la fin" et il le fait. (Le rest des commands signifie "imprimer le tampon" et "sortir", qui sont également lisibles).
NB: La command ex
donnée ci-dessus échouera si elle reçoit less de 2 lignes en input.
Pour en savoir plus:
Un petit extrait de python
:
#!/usr/bin/env python3 import sys file_ = sys.argv[1] lines = int(sys.argv[2]) with open(file_) as f: f = f.readlines() out = f[lines:] + f[:lines] print(''.join(out), end='')
Passez le nom de file en tant que premier argument et le nombre de lignes à déplacer en tant que second argument.
Exemple:
$ cat input.txt 44444 55555 11111 22222 33333 $ ./sw_lines.py input.txt 2 11111 22222 33333 44444 55555 $ ./sw_lines.py input.txt 4 33333 44444 55555 11111 22222
Si vous pouvez stocker toute la sortie en memory:
data=$(some command) n=42 # or whatever { tail -n +$((n+1)) <<<"$data"; head -n $n <<<"$data"; } > outputfile
Voici une autre option qui nécessite GNU sed
:
(x=$(gsed -u 3q);cat;printf %s\\n "$x")
-u
rend GNU sed
unbuffered afin que la command sed
ne consum pas plus de 3 lignes de STDIN. La substitution de command supprime les lignes vides, de sorte que la command n'inclut pas de lignes vides à la fin de la sortie si les troisième, troisième et deuxième ou troisième, deuxième et première lignes sont vides.
Vous pouvez également faire quelque chose comme ceci:
tee >(sponge /dev/stdout|sed -u 3q)|sed 1,3d
Sans sponge /dev/stdout|
la command échouerait avec de longues inputs. sponge /dev/stdout
peut également être remplacé par tac|tac
, même si cela imprime par exemple a\ncb
si l'input est a\nb\nc
où \n
est un saut de ligne, ou avec (x=$(cat);printf %s\\n "$x")
, même si cela supprime les lignes vides de la fin de l'input. La command ci-dessus supprime la première ligne lorsque le nombre de lignes de l'input est un ou deux.