Один надійний спосіб bash - це розширити масив і вивести лише перший елемент:
pattern="*.txt"
files=( $pattern )
echo "${files[0]}" # printf is safer!
(Можна навіть просто echo $files
, що відсутній індекс трактується як [0].)
Це безпечно обробляє простір / вкладку / новий рядок та інші метахарактери при розширенні назви файлів. Зауважте, що фактичні параметри локалі можуть змінити те, що є "першим".
Ви також можете це робити в інтерактивному режимі з функцією завершення 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
команди (переосмислюючи нормальне завершення). Додатково "*" додано в код вище, ви можете просто натиснути вкладку на часткове ім'я файлу, і, сподіваємось, правильна річ станеться.
Код злегка перекручений, а не встановити чи припустити nullglob
( shopt -s nullglob
), що ми перевіряємо, compgen -G
може розширити глобус на деякі збіги, потім ми безпечно розширимось у масив і, нарешті, встановимо КОМПЛЕКТНО, щоб цитування надійне.
Ви можете частково це зробити (програмно розгорнути глобус) за допомогою bash's compgen -G
, але це не надійно, оскільки виводить без котирування stdout.
Як завжди, завершення є досить загрозливим, це порушує завершення інших речей, включаючи змінні середовища ( детальну інформацію про імітацію поведінки за замовчуванням див. У цій _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 (див. FAQ 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
і може, а може, і не складе), але в іншому випадку це досить великий молоток для такої невеликої проблеми ;-)