Jednym z solidnych sposobów bash jest rozwinięcie do tablicy i wyprowadzenie tylko pierwszego elementu:
pattern="*.txt"
files=( $pattern )
echo "${files[0]}" # printf is safer!
(Możesz nawet po prostu echo $files
, brakujący indeks jest traktowany jako [0].)
To bezpiecznie obsługuje spację / tab / znak nowej linii i inne metaznaki podczas rozwijania nazw plików. Pamiętaj, że obowiązujące ustawienia regionalne mogą zmienić to, co jest „pierwsze”.
Możesz to również zrobić interaktywnie za pomocą funkcji uzupełniania 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
Powoduje to powiązanie _echo
funkcji z uzupełnieniem argumentów echo
polecenia (zastępując normalne zakończenie). Dodatkowy „*” jest dołączony do powyższego kodu, możesz po prostu nacisnąć tabulację na częściowej nazwie pliku i mam nadzieję, że coś dobrego się wydarzy.
Kod jest nieco zawiły, zamiast ustawiania lub zakładania nullglob
( shopt -s nullglob
) sprawdzamy, czy compgen -G
można rozszerzyć glob do niektórych dopasowań, następnie bezpiecznie rozwijamy do tablicy, a na końcu ustawiamy COMPREPLY, aby cytowanie było solidne.
Możesz częściowo to zrobić (programowo rozwinąć glob) za pomocą bash compgen -G
, ale nie jest to niezawodne, ponieważ wypisywane jest nie przywołane na standardowe wyjście.
Jak zwykle, uzupełnianie jest dość obciążone, co przerywa uzupełnianie innych rzeczy, w tym zmiennych środowiskowych (zobacz tutaj_bash_def_completion()
funkcję , aby uzyskać szczegółowe informacje na temat emulacji domyślnego zachowania).
Możesz także użyć compgen
poza funkcją uzupełniania:
files=( $(compgen -W "$pattern") )
Należy zauważyć, że „~” nie jest globem, jest obsługiwane przez bash na osobnym etapie ekspansji, podobnie jak zmienne $ i inne rozszerzenia. compgen -G
po prostu dokonuje globowania nazw plików, ale compgen -W
zapewnia wszystkie domyślne rozszerzenia bash, choć być może zbyt wiele rozszerzeń (w tym ``
i $()
). W przeciwieństwie do -G
, -W
jest bezpiecznie cytowany (nie umiem wyjaśnić różnicy). Ponieważ chodzi o -W
to, że rozwija on tokeny, oznacza to, że rozwinie „a” do „a”, nawet jeśli taki plik nie istnieje, więc być może nie jest idealny.
Jest to łatwiejsze do zrozumienia, ale może mieć niepożądane skutki uboczne:
_echo() {
local cur=${COMP_WORDS[COMP_CWORD]}
local files=( $(compgen -W "$cur") )
printf -v COMPREPLY %q "${files[0]}"
}
Następnie:
touch $'curious \n filename'
echo curious*
tab
Zwróć uwagę na użycie, printf %q
aby bezpiecznie podać wartości.
Ostatnią opcją jest użycie wyjścia rozdzielanego cyframi 0 w narzędziach GNU (zobacz bash FAQ ):
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 )
Ta opcja daje ci nieco większą kontrolę nad kolejnością sortowania (kolejność przy rozszerzaniu globu będzie zależała od twoich ustawień regionalnych / LC_COLLATE
i może, ale nie musi składać), ale poza tym jest dość dużym młotem dla tak małego problemu ;-)