Как получить первое слово строки?

43

Когда я 'echo *' получаю следующий вывод:

file1 file2 file3 ...

То, что я хочу, это выбрать первое слово. Как я могу продолжить?

vdegenne
источник
1
@mattdm Использование lsне будет работать, если одно из имен файлов содержит пробел.
helpermethod
2
Как вы определяете слово ? Если первый файл Sunset on a beach.jpg, это должно быть Sunsetили полное имя файла? Как насчет Sea, sex and sun.ogg? Sea, Sea,Или имя весь файл?
Стефан Шазелас
@mattdm ls | head -1дает мне случайные вещи, такие как a.patch p.pyне первое слово и даже файлы в алфавитном порядке.
phuclv

Ответы:

52

Вы можете передать это через awk и заставить его повторить первое слово

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

или вы сокращаете строку и выбираете первое слово:

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

или вы трубите его через sed и удалите все, кроме первого слова

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

Добавил | head -n1для удовлетворения придирки. Если ваша строка содержит символы новой строки | head -n1, сначала будет выбрана первая строка, прежде чем важные команды выберут первое слово из переданной ей строки.

Bananguin
источник
1
Возвращает первое слово каждой строки, а не первое слово.
Стефан Шазелас
2
Интересно, сколько строк echo *генерирует
Bananguin
Это зависит от того, сколько файлов имеют символы новой строки в своем имени, или в зависимости от среды, или от того, как был скомпилирован bash, или от того, какой файл называется -eили -ee... появляется в списке, сколько раз \nпоявляется в имени файла. Если есть файл с именем -n, он может вообще не вернуть ни одной строки ...
Стефан Шазелас
Ну, мы все еще говорим о bash и 1. обычно bash не передает строку с символами новой строки как одну строку с новыми строками 2. очень сложно и необычно (невозможно?) Иметь новую строку в имени файла 3. a \ n в имя файла будет отображаться как \ n 4. 3 относится к именам файлов, начинающимся с - 5. даже при вызове с -n или -e echo откроет стандартный вывод и закроет его, когда это будет сделано, конечно, он вернет строку, и при по крайней мере, одну строку, в этом отношении 6. я отредактировал мой совет, по крайней мере, позаботиться о многолинейной проблеме
Bananguin
1
Все 5 баллов ложные. Попробуйте в пустом каталоге: touch '$a\nb' 'a\nb'; env BASHOPTS=xpg_echo bash -c 'echo * | wc -l'( xpg_echoвключен везде, где bashтребуется совместимость с Unix). А в другой пустой каталог: touch ./-n; bash -c 'echo * | wc -l'. Строка - это последовательность символов, оканчивающаяся символом новой строки. Если echoне выводить символ новой строки, он не выводит никакой строки. Поведение текстовых утилит, например cut, awkили sedне определено, если ввод содержит дополнительные символы после последнего символа новой строки, и поведение варьируется в зависимости от реализации.
Стефан Шазелас
18

Предположим, что это оболочка posixy ( /bin/shили /bin/bashможет сделать это)

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

Конструкция ${all%% *}является примером удаления подстроки . На %%средства удаления самого длинного матча *(пробел , затем что - нибудь) с правого конца переменных all. Вы можете прочитать больше о работе со строками здесь .

Это решение предполагает, что разделитель является пробелом. Если вы делаете это с именами файлов, то любой с пробелами сломает его.

starfry
источник
Хороший. Но мне понравилась простая и более не хакерская другая версия с headиcut
Anwar
4
ИМО, head, cut & sed менее просты. Зачем создавать другой инструмент, когда встроенная подстановка параметров делает работу эффективно. Этот ответ является наиболее эффективным и наиболее переносимым способом выделения первого слова из списка слов, разделенных пробелами (и это все, что запрашивает OP).
Хуан
7

Предполагая, что вы действительно хотите первое имя файла, а не первое слово , вот способ, который не ломается на пустом месте:

shopt -s nullglob
files=(*)
printf '%s\n' "${files[0]}"
Крис Даун
источник
1
Первое слово было бы тоже легко:files=($(echo *))
Хауке Лагинг
2
Он будет разбит на «-n», «-e», «-ne», «-Enenene» ... и, в зависимости от того, как он bashбыл скомпилирован или от окружения, возможно, от символов обратной косой черты.
Стефан Шазелас
2
@ HaukeLaging, вам нужно отключить глобализация. Как:, в text=$(echo *); set -f; files=($text)противном случае можно использовать больше подстановочных знаков.
Стефан Шазелас
3
иfiles=$(echo *); echo ${files%% *}
vdegenne
1
@memnoch_proxy Он будет разбиваться на имена файлов, содержащие пробелы, используйте его с осторожностью.
Крис Даун
5

Вы можете использовать позиционные параметры

set -- *
echo "$1"
Гленн Джекман
источник
3
Имейте в виду, что это уничтожит любые другие аргументы в вашем скрипте, если они не выполняются во вспомогательной области видимости. Это также расширится, *если в каталоге нет файлов.
Крис Даун
shopt -s nullglobбы справиться с этим
Гленн Джекман
1

Получение всего первого имени файла:

shopt -s nullglob
printf '%s\000' * | grep -z -m 1 '^..*$'
printf '%s\000' * | ( IFS="" read -r -d "" var; printf '%s\n' "$var" )
Markle
источник