Commande Shell / Bash pour obtenir la nième ligne de STDOUT
Y a-t-il une commande bash qui vous permettra d'obtenir la nième ligne de STDOUT?
C'est-à-dire, quelque chose qui prendrait cette
$ ls -l
-rw-r--r--@ 1 root wheel my.txt
-rw-r--r--@ 1 root wheel files.txt
-rw-r--r--@ 1 root wheel here.txt
Et faites quelque chose comme
$ ls -l | magic-command 2
-rw-r--r--@ 1 root wheel files.txt
Je me rends compte que ce serait une mauvaise pratique lors de l'écriture de scripts destinés à être réutilisés, mais lorsque vous travaillez avec le shell au jour le jour, il me serait utile de pouvoir filtrer mon STDOUT de cette manière.
Je me rends également compte que ce serait une commande semi-triviale à écrire (buffer STDOUT, retourner une ligne spécifique), mais je veux savoir s'il y a une commande shell standard pour faire ceci qui serait disponible sans que je laisse tomber un script en place.
13 réponses
En utilisant sed
, juste pour la variété:
ls -l | sed -n 2p
L'utilisation de cette alternative, qui semble plus efficace puisqu'elle arrête la lecture de l'entrée lorsque la ligne requise est imprimée, peut générer un SIGPIPE dans le processus d'alimentation, qui peut à son tour générer un message d'erreur indésirable:
ls -l | sed -n -e '2{p;q}'
J'ai vu assez souvent que j'utilise habituellement le premier (ce qui est plus facile à taper, de toute façon), bien que ls
ne soit pas une commande qui se plaint quand elle obtient SIGPIPE.
Pour une plage de lignes:
ls -l | sed -n 2,4p
Pour plusieurs plages de lignes:
ls -l | sed -n -e 2,4p -e 20,30p
ls -l | sed -n -e '2,4p;20,30p'
Alternative à la belle façon tête / queue:
ls -al | awk 'NR==2'
Ou
ls -al | sed -n '2p'
À Partir de sed1line:
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3, efficient on large files
À Partir de awk1line:
# print line number 52
awk 'NR==52'
awk 'NR==52 {print;exit}' # more efficient on large files
Par souci d'exhaustivité ;-)
Code Plus Court
find / | awk NR==3
Durée de vie plus courte
find / | awk 'NR==3 {print $0; exit}'
Essayez cette version sed
:
ls -l | sed '2 ! d'
Il dit "supprimer toutes les lignes qui ne sont pas la seconde".
Vous pouvez utiliser awk:
ls -l | awk 'NR==2'
Mettre à jour
Le code ci-dessus n'obtiendra pas ce que nous voulons à cause d'une erreur ponctuelle: la première ligne de la commande ls-l est la ligne Total. Pour cela, le code révisé suivant fonctionnera:
ls -l | awk 'NR==3'
Perl est-il facilement disponible pour vous?
$ perl -n -e 'if ($. == 7) { print; exit(0); }'
Remplacez évidemment le nombre que vous voulez par 7.
Une autre affiche suggérée
ls -l | head -2 | tail -1
Mais si vous dirigez la tête dans la queue, il semble que tout jusqu'à la ligne N soit traité deux fois.
Queue sifflante dans la tête
ls -l | tail -n +2 | head -n1
Serait plus efficace?
Oui, le moyen le plus efficace (comme l'a déjà souligné Jonathan Leffler) est d'utiliser sed avec print & quit:
set -o pipefail # cf. help set
time -p ls -l | sed -n -e '2{p;q;}' # only print the second line & quit (on Mac OS X)
echo "$?: ${PIPESTATUS[*]}" # cf. man bash | less -p 'PIPESTATUS'
Hmm
Sed n'a pas fonctionné dans mon cas. Je propose:
Pour les lignes "impaires" 1,3,5,7... ls |awk '0 == (N+1) % 2'
Pour les lignes "paires" 2,4,6,8 ls /awk '0 = =(NR) % 2'
Pour plus d'exhaustivité..
ls -l | (for ((x=0;x<2;x++)) ; do read ; done ; head -n1)
Jetez les lignes jusqu'à ce que vous arriviez à la seconde, puis imprimez la première ligne après cela. Donc, il imprime la 3ème ligne.
Si c'est juste la deuxième ligne..
ls -l | (read; head -n1)
Mettez autant de lectures que nécessaire.
J'ai ajouté cela dans mon .bash_profile
function gdf(){
DELETE_FILE_PATH=$(git log --diff-filter=D --summary | grep delete | grep $1 | awk '{print $4}')
SHA=$(git log --all -- $DELETE_FILE_PATH | grep commit | head -n 1 | awk '{print $2}')
git show $SHA -- $DELETE_FILE_PATH
}
Et ça marche
gdf <file name>