Comment obtenir le premier mot d'une chaîne?

43

Quand 'echo *' j'obtiens la sortie suivante:

file1 file2 file3 ...

Ce que je veux, c'est choisir le premier mot. Comment puis-je procéder?

Vdegenne
la source
1
@mattdm L'utilisation lsne fonctionnera pas si l'un des noms de fichier contient un blanc.
helpermethod
2
Comment définissez-vous le mot ? Si le premier fichier existe Sunset on a beach.jpg, doit-il s'agir d' Sunsetun nom de fichier complet? Qu'en est- il Sea, sex and sun.ogg? Sea, Sea,ou le nom du fichier entier?
Stéphane Chazelas
@mattdm ls | head -1me donne des choses aléatoires comme a.patch p.pyce qui n'est pas le premier mot et même pas les fichiers dans l'ordre alphabétique.
phuclv

Réponses:

52

Vous pouvez le faire passer à travers awk et faire en sorte qu'il répète le premier mot

echo * | head -n1 | awk '{print $1;}'

ou vous coupez la chaîne et sélectionnez le premier mot:

echo *  | head -n1 | cut -d " " -f1

ou vous le dirigez et laissez-le supprimer tout, sauf le premier mot

echo * | head -n1 | sed -e 's/\s.*$//'

Ajouté le | head -n1pour satisfaire les nitpickers. Si votre chaîne contient des nouvelles lignes | head -n1, sélectionnez la première ligne avant que les commandes importantes ne sélectionnent le premier mot de la chaîne qui lui est transmise.

Bananguin
la source
1
Le renverrait le premier mot de chaque ligne, pas le premier mot.
Stéphane Chazelas
2
Je me demande combien de lignes echo *génèrent
Bananguin
Cela dépend du nombre de fichiers avec des caractères de nouvelle ligne dans leur nom ou en fonction de l'environnement ou de la manière dont bash a été compilé ou encore si un fichier appelé -eou -ee... apparaît dans la liste, combien de fois il \napparaît dans un nom de fichier. S'il y a un fichier appelé -n, il risque de ne pas renvoyer de ligne du tout ...
Stéphane Chazelas
Eh bien, nous parlons toujours de bash et 1. d'habitude bash ne transmettra pas une chaîne avec des nouvelles lignes comme une chaîne avec de nouvelles lignes 2. il est très difficile et inhabituel (impossible?) D'avoir une nouvelle ligne dans un nom de fichier 3. a \ n in un nom de fichier apparaîtra sous la forme \ n 4. 3 est valable pour les noms de fichiers commençant par - 5. même lorsque vous appelez avec -n ou -e, echo ouvrira stdout et le fermera à la fin. Bien sûr, il retournera une ligne et au moins une chaîne, d'ailleurs 6. J'ai modifié mon conseil pour au moins prendre soin du problème multiligne
Bananguin
1
Tous les 5 points sont faux. Essayez dans un répertoire vide: touch '$a\nb' 'a\nb'; env BASHOPTS=xpg_echo bash -c 'echo * | wc -l'( xpg_echoest activé partout où il bashest requis d'être conforme à Unix). Et dans un autre répertoire vide: touch ./-n; bash -c 'echo * | wc -l'. Une ligne est une séquence de caractères terminée par un caractère de nouvelle ligne. Si echone produit pas de caractère de nouvelle ligne, aucune ligne n'est affichée. Le comportement des utilitaires de texte tels que cut, awkou sedn'est pas spécifié, si l'entrée comporte des caractères supplémentaires après le dernier caractère de nouvelle ligne et que le comportement varie selon les implémentations.
Stéphane Chazelas
18

En supposant un shell posixy ( /bin/shou /bin/bashpeut le faire)

all=$(echo *)
first=${all%% *}

La construction ${all%% *}est un exemple de suppression de sous - chaîne . Les %%moyens suppriment la correspondance la plus longue de *(un espace suivi de rien) de l'extrémité droite de la variable all. Vous pouvez en savoir plus sur la manipulation de chaîne ici .

Cette solution suppose que le séparateur est un espace. Si vous faites cela avec des noms de fichiers, tout espace avec des espaces le cassera.

starfry
la source
Joli. Mais j'ai aimé l'autre version simple et plus non-hacky avec headetcut
Anwar le
4
IMO, head, cut & sed sont moins simples. Pourquoi créer un autre outil lorsque la substitution de paramètres intégrée effectue le travail efficacement. Cette réponse est le moyen le plus efficace et le plus portable de sélectionner le premier mot d'une liste de mots séparés par des espaces (ce qui correspond à tous les OP demandés).
Juan
7

En supposant que vous vouliez vraiment le premier nom de fichier et non le premier mot , voici une solution qui ne casse pas les blancs:

shopt -s nullglob
files=(*)
printf '%s\n' "${files[0]}"
Chris Down
la source
1
Le premier mot serait aussi facile:files=($(echo *))
Hauke ​​Laging le
2
Il se briserait sur "-n", "-e", "-ne", "-Enenene" ..., et selon la façon dont il a bashété compilé ou l'environnement, éventuellement sur des barres obliques inverses.
Stéphane Chazelas
2
@HaukeLaging, vous devez désactiver le globbing. Comme text=$(echo *); set -f; files=($text):, sinon plus de jokers pourraient être étendus.
Stéphane Chazelas
3
etfiles=$(echo *); echo ${files%% *}
vdegenne
1
@ memnoch_proxy Cela va casser les noms de fichiers contenant des espaces, utilisez-le avec prudence.
Chris Down
5

Vous pouvez utiliser les paramètres de position

set -- *
echo "$1"
Glenn Jackman
la source
3
Sachez que cela détruira tous les autres arguments de votre script, sauf s’il est exécuté dans une étendue auxiliaire. Il sera également étendu à *s'il n'y a aucun fichier dans le répertoire.
Chris Down
shopt -s nullglobtraiterait que
glenn JACKMAN
3

Cochez l'une des alternatives suivantes:

$ FILE=($(echo *))
$ FILE=$(echo * | grep -o "^\S*")
$ FILE=$(echo * | grep -o "[^ ]*")
$ FILE=$(find . -type f -print -quit)

Ensuite, vous pouvez l’imprimer via echo $FILE.

Voir aussi: greple seul premier mot de la sortie?

Kenorb
la source
1

Obtenir le premier nom de fichier complet:

shopt -s nullglob
printf '%s\000' * | grep -z -m 1 '^..*$'
printf '%s\000' * | ( IFS="" read -r -d "" var; printf '%s\n' "$var" )
markle
la source