Один надежный способ в bash - развернуть в массив и вывести только первый элемент:
pattern="*.txt"
files=( $pattern )
echo "${files[0]}" # printf is safer!
(Вы можете даже просто echo $files
, отсутствующий индекс обрабатывается как [0].)
Это безопасно обрабатывает пробел / tab / newline и другие метасимволы при расширении имен файлов. Обратите внимание, что действующие настройки локали могут изменить то, что «первое».
Вы также можете сделать это интерактивно с помощью функции завершения bash :
_echo() {
local cur=${COMP_WORDS[COMP_CWORD]} # string to expand
if compgen -G "$cur*" > /dev/null; then
local files=( ${cur:+$cur*} ) # don't expand empty input as *
[ ${#files} -ge 1 ] && COMPREPLY=( "${files[0]}" )
fi
}
complete -o bashdefault -F _echo echo
Это связывает _echo
функцию для завершения аргументовecho
команды (переопределяя нормальное завершение). В приведенном выше коде добавлено дополнительное «*», вы можете просто нажать «tab» на частичном имени файла, и, надеюсь, правильная вещь произойдет.
Код немного запутанным, а не набор или предположить nullglob
( shopt -s nullglob
) мы проверяем , compgen -G
можно расширить Glob в некоторых матчах, то мы расширим благополучно в массив, и , наконец , установить COMPREPLY так , чтобы процитировать надежен.
Вы можете частично сделать это (программно расширить глобус) с помощью bash compgen -G
, но это не надежно, так как выводит без кавычек в стандартный вывод.
Как обычно, завершение довольно чревато, это нарушает завершение других вещей, включая переменные среды (см. _bash_def_completion()
Функцию здесь для деталей эмулирует поведение по умолчанию).
Вы также можете просто использовать compgen
вне функции завершения:
files=( $(compgen -W "$pattern") )
Следует отметить, что «~» - это не глобус, он обрабатывается bash на отдельной стадии раскрытия, как и переменные $ и другие раскрытия. compgen -G
просто выполняет глобализацию имени файла, но compgen -W
дает вам все расширения bash по умолчанию, хотя, возможно, слишком много расширений (включая ``
и $()
). В отличие от -G
, -W
это безопасно цитируется (я не могу объяснить несоответствие). Поскольку цель -W
состоит в том, что он расширяет токены, это означает, что он расширит «a» до «a», даже если такого файла не существует, поэтому, возможно, он не идеален.
Это легче понять, но может иметь нежелательные побочные эффекты:
_echo() {
local cur=${COMP_WORDS[COMP_CWORD]}
local files=( $(compgen -W "$cur") )
printf -v COMPREPLY %q "${files[0]}"
}
Затем:
touch $'curious \n filename'
echo curious*
tab
Обратите внимание на использование printf %q
для безопасного цитирования значений.
Последний вариант - использовать вывод с разделителями 0 для утилит GNU (см. Часто задаваемые вопросы по bash ):
pattern="*.txt"
while IFS= read -r -d $'\0' filename; do
printf '%q' "$filename";
break;
done < <(find . -maxdepth 1 -name "$pattern" -printf "%f\0" | sort -z )
Эта опция дает вам немного больше контроля над порядком сортировки (порядок при развертывании глоба будет зависеть от вашей локали / LC_COLLATE
и может или не может сложить регистр), но в остальном довольно большой молоток для такой маленькой проблемы ;-)