¿Cómo obtener la primera palabra de una cadena?

43

Cuando 'echo *' obtengo el siguiente resultado:

file1 file2 file3 ...

Lo que quiero es elegir la primera palabra. ¿Cómo puedo proceder?

vdegenne
fuente
1
@mattdm El uso lsno funcionará si uno de los nombres de archivo contiene un espacio en blanco.
helpermethod
2
¿Cómo se define la palabra ? Si el primer archivo es Sunset on a beach.jpg, ¿debería serlo Sunseto el nombre completo del archivo? ¿Qué hay de Sea, sex and sun.ogg? Sea, Sea,O la totalidad nombre de archivo?
Stéphane Chazelas
@mattdm ls | head -1me da cosas aleatorias como a.patch p.pycuál no es la primera palabra y ni siquiera los archivos en orden alfabético.
phuclv

Respuestas:

52

Puedes canalizarlo a través de awk y hacer que se haga eco de la primera palabra

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

o cortas la cadena y seleccionas la primera palabra:

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

o lo canalizas a través de sed y haces que elimine todo menos la primera palabra

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

Se agregó el | head -n1para satisfacer a los nitpickers. En caso de que su cadena contenga nuevas | head -n1líneas, primero seleccionará la primera línea antes de que los comandos importantes seleccionen la primera palabra de la cadena que se le pasó.

Bananguin
fuente
1
El devolvería la primera palabra de cada línea, no la primera palabra.
Stéphane Chazelas
2
echo *
Me
Eso depende de cuántos archivos tengan caracteres de nueva línea en su nombre o según el entorno o cómo se compiló bash o si algún archivo llamado -eo -ee... aparece en la lista, cuántas veces \naparece en un nombre de archivo. Si hay un archivo llamado -n, es posible que ni siquiera devuelva ninguna línea ...
Stéphane Chazelas
Bueno, todavía estamos hablando de bash y 1. generalmente bash no pasará una cadena con líneas nuevas como una cadena con líneas nuevas 2. es muy difícil e inusual (¿imposible?) Tener una nueva línea en un nombre de archivo 3. a \ n en un nombre de archivo aparecerá como \ n 4. 3 retenciones para nombres de archivo que comienzan con - 5. incluso cuando se llama con -n o -e echo se abrirá stdout y se cerrará cuando esté hecho, por supuesto, devolverá una línea, y en al menos una cadena, para el caso 6.
edité
1
Los 5 puntos son falsos. Pruebe en un directorio vacío: touch '$a\nb' 'a\nb'; env BASHOPTS=xpg_echo bash -c 'echo * | wc -l'( xpg_echoestá habilitado donde bashsea ​​necesario para ser compatible con Unix). Y en otro directorio vacío: touch ./-n; bash -c 'echo * | wc -l'. Una línea es una secuencia de caracteres terminados por un carácter de nueva línea. Si echono genera un carácter de nueva línea, no genera ninguna línea. El comportamiento de las utilidades de texto como cut, awko sedno se especifica si la entrada tiene caracteres adicionales después del último carácter de nueva línea y el comportamiento varía según las implementaciones.
Stéphane Chazelas
18

Asumiendo un shell posixy ( /bin/sho /bin/bashpuede hacer esto)

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

La construcción ${all%% *}es un ejemplo de eliminación de subcadenas . Los %%medios eliminan la coincidencia más larga de *(un espacio seguido de cualquier cosa) desde el extremo derecho de la variable all. Puedes leer más sobre la manipulación de cadenas aquí .

Esta solución supone que el separador es un espacio. Si está haciendo esto con nombres de archivo, cualquiera con espacios lo romperá.

starfry
fuente
Buena esa. Pero me gustó la otra versión simple y más no hacky con headycut
Anwar
44
OMI, cabeza, corte y sed son menos simples. ¿Por qué generar otra herramienta cuando la sustitución de parámetros incorporados hace el trabajo de manera eficiente? Esta respuesta es la forma más eficiente y portátil de elegir la primera palabra de una lista de palabras separadas por espacios (que es todo lo que solicitó el OP).
Juan
7

Suponiendo que realmente desea el primer nombre de archivo y no la primera palabra , aquí hay una forma que no se rompe en espacios en blanco:

shopt -s nullglob
files=(*)
printf '%s\n' "${files[0]}"
Chris Down
fuente
1
La primera palabra también sería fácil:files=($(echo *))
Hauke ​​Laging
2
Se rompería en "-n", "-e", "-ne", "-Enenene" ..., y dependiendo de cómo bashse compiló o del entorno, posiblemente en caracteres de barra invertida.
Stéphane Chazelas
2
@HaukeLaging, deberías deshabilitar el globbing. Me gusta: de lo text=$(echo *); set -f; files=($text)contrario, se podrían expandir más comodines.
Stéphane Chazelas
3
yfiles=$(echo *); echo ${files%% *}
vdegenne
1
@memnoch_proxy Se romperá en los nombres de archivo que contengan espacios en blanco, úselo con precaución.
Chris Down
5

Puedes usar los parámetros posicionales

set -- *
echo "$1"
Glenn Jackman
fuente
3
Tenga en cuenta que esto destruirá cualquier otro argumento de su script, a menos que se ejecute en un ámbito auxiliar. También se expandirá a *si no hay archivos en el directorio.
Chris Down
shopt -s nullglobmanejaría eso
glenn jackman
3

Marque una de las siguientes alternativas:

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

Luego puede imprimirlo a través de echo $FILE.

Ver también: ¿ grepla única primera palabra de la salida?

kenorb
fuente
1

Obteniendo todo el primer nombre de archivo:

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