बैश में एक मजबूत तरीका एक सरणी में विस्तार करना है, और केवल पहले तत्व का उत्पादन करना है:
pattern="*.txt"
files=( $pattern )
echo "${files[0]}" # printf is safer!
(आप यहां तक कि बस echo $files
, एक लापता सूचकांक को [0] माना जा सकता है।)
यह सुरक्षित रूप से अंतरिक्ष / टैब / न्यूलाइन और अन्य मेटाचैकर को संभालता है जब फाइलनाम का विस्तार करता है। ध्यान दें कि प्रभावी रूप से स्थानीय सेटिंग्स "पहले" क्या बदल सकती हैं।
आप इसे बश समापन समारोह के साथ अंतःक्रियात्मक रूप से भी कर सकते हैं :
_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
कुछ मैचों के लिए ग्लोब विस्तार कर सकते हैं, तो हम एक सरणी में सुरक्षित रूप से विस्तार, और अंत में COMPREPLY ताकि हवाले से मजबूत है निर्धारित किया है।
आप आंशिक रूप से ऐसा कर सकते हैं (प्रोग्रामेटिक रूप से ग्लोब का विस्तार कर सकते हैं ) बैश के साथ compgen -G
, लेकिन यह मजबूत नहीं है क्योंकि यह स्टडआउट के लिए अयोग्य है।
हमेशा की तरह, पूरा होने के बजाय भयावह है, यह पर्यावरण चर सहित अन्य चीजों के पूरा होने को तोड़ता है ( डिफ़ॉल्ट व्यवहार का अनुकरण करने के विवरण के लिए यहां_bash_def_completion()
फ़ंक्शन देखें )।
तुम भी compgen
एक पूरा समारोह के बाहर उपयोग कर सकते हैं :
files=( $(compgen -W "$pattern") )
ध्यान देने वाली बात यह है कि "~" एक ग्लोब नहीं है, इसे विस्तार के एक अलग चरण में बैश द्वारा नियंत्रित किया जाता है, क्योंकि $ चर और अन्य विस्तार हैं। compgen -G
बस ग्लोबिंग को नामांकित करता है, लेकिन compgen -W
आपको सभी बैश के डिफ़ॉल्ट विस्तार देता है, हालांकि संभवतः बहुत सारे विस्तार (सहित ``
और $()
)। विपरीत -G
, -W
है सुरक्षित रूप से उद्धृत (मैं असमानता की व्याख्या नहीं कर सकते हैं)। चूंकि इसका उद्देश्य -W
यह है कि यह टोकन का विस्तार करता है, इसका मतलब है कि यह "ए" से "ए" तक विस्तृत होगा, भले ही ऐसी कोई फ़ाइल मौजूद न हो, इसलिए यह शायद आदर्श नहीं है।
यह समझना आसान है, लेकिन इसके अवांछित दुष्प्रभाव हो सकते हैं:
_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
मानों को सुरक्षित रूप से उद्धृत करने के उपयोग पर ध्यान दें ।
एक अंतिम विकल्प GNU उपयोगिताओं के साथ 0-सीमांकित आउटपुट का उपयोग करना है ( 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 )
यह विकल्प आपको सॉर्टिंग ऑर्डर पर थोड़ा अधिक नियंत्रण देता है (एक ग्लोब का विस्तार करते समय ऑर्डर आपके लोकेल के अधीन होगा / LC_COLLATE
और केस को फोल्ड नहीं कर सकता है), लेकिन अन्यथा ऐसी छोटी समस्या के लिए एक बड़ा हथौड़ा है;;