इस उत्तर में किसी भी प्रकार की फ़ाइलों के लिए समाधान हैं । न्यूलाइन्स या स्पेस के साथ।
हाल ही में बाश के साथ-साथ प्राचीन बाश और यहां तक कि पुराने पॉश गोले के समाधान भी हैं।
इस उत्तर में नीचे सूचीबद्ध पेड़ [1] का उपयोग परीक्षणों के लिए किया जाता है।
चुनते हैं
select
किसी सरणी के साथ काम करना आसान है :
$ dir='deep/inside/a/dir'
$ arr=( "$dir"/* )
$ select var in "${arr[@]}"; do echo "$var"; break; done
या स्थितिगत मापदंडों के साथ:
$ set -- "$dir"/*
$ select var; do echo "$var"; break; done
तो, एकमात्र वास्तविक समस्या एक सरणी के अंदर या स्थितीय पैरामीटर के अंदर "फ़ाइलों की सूची" (सही ढंग से सीमांकित) प्राप्त करना है। पढ़ते रहिये।
दे घुमा के
मैं आपको बैश के साथ रिपोर्ट करने वाली समस्या नहीं देखता। बैश किसी दिए गए निर्देशिका के अंदर खोज करने में सक्षम है:
$ dir='deep/inside/a/dir'
$ printf '<%s>\n' "$dir"/*
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
या, अगर आपको एक लूप पसंद है:
$ set -- "$dir"/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
ध्यान दें कि ऊपर दिया गया सिंटैक्स किसी भी (उचित) शेल (कम से कम csh नहीं) के साथ सही ढंग से काम करेगा।
एकमात्र सीमा जो ऊपर सिंटैक्स है, वह अन्य निर्देशिकाओं में उतरना है।
लेकिन मार सकता है:
$ shopt -s globstar
$ set -- "$dir"/**/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
केवल कुछ फ़ाइलों का चयन करने के लिए (जैसे कि फ़ाइल में समाप्त होने वाले ) सिर्फ * बदलें:
$ set -- "$dir"/**/*file
$ printf '<%s>\n' "$@"
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/zz last file>
मजबूत
जब आप शीर्षक में "स्थान- सुरक्षित " रखते हैं, तो मैं यह मानने जा रहा हूं कि आपका क्या मतलब था " मजबूत "।
रिक्त स्थान (या newlines) के बारे में मजबूत होने का सबसे सरल तरीका इनपुट के प्रसंस्करण को अस्वीकार करना है जिसमें रिक्त स्थान (या newlines) है। शेल में ऐसा करने का एक बहुत ही सरल तरीका एक त्रुटि के साथ बाहर निकलना है यदि कोई फ़ाइल नाम किसी स्थान के साथ फैलता है। ऐसा करने के कई तरीके हैं, लेकिन सबसे अधिक कॉम्पैक्ट (और पॉज़िक्स) (लेकिन एक डायरेक्टरी कंटेंट तक सीमित है, जिसमें suddirectories नाम और डॉट-फाइल्स से बचना शामिल है):
$ set -- "$dir"/file* # read the directory
$ a="$(printf '%s' "$@" x)" # make it a long string
$ [ "$a" = "${a%% *}" ] || echo "exit on space" # if $a has an space.
$ nl='
' # define a new line in the usual posix way.
$ [ "$a" = "${a%%"$nl"*}" ] || echo "exit on newline" # if $a has a newline.
यदि उपयोग किए गए समाधान में से किसी भी आइटम में मजबूत है, तो परीक्षण को हटा दें।
बाश में, उप-निर्देशिकाओं का परीक्षण एक साथ किया जा सकता है ** ऊपर बताया गया है।
डॉट फाइलें शामिल करने के कुछ तरीके हैं, Posix समाधान है:
set -- "$dir"/* "$dir"/.[!.]* "$dir"/..?*
खोज
यदि खोज किसी कारण से उपयोग की जानी चाहिए, तो सीमांकक को NUL (0x00) से बदलें।
बैश 4.4+
$ readarray -t -d '' arr < <(find "$dir" -type f -name file\* -print0)
$ printf '<%s>\n' "${arr[@]}"
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/file>
bash 2.05+
i=1 # lets start on 1 so it works also in zsh.
while IFS='' read -d '' val; do
arr[i++]="$val";
done < <(find "$dir" -type f -name \*file -print0)
printf '<%s>\n' "${arr[@]}"
POSIXLY
एक वैध POSIX समाधान बनाने के लिए जहां पाते हैं कि एक NUL सीमांकक नहीं है और पढ़ने के लिए कोई नहीं -d
(न ही -a
) है, हमें पूरी तरह से अलग अनुलोम की आवश्यकता है।
हमें -exec
कॉल से कॉल करने के लिए एक कॉम्प्लेक्स का उपयोग करने की आवश्यकता है :
find "$dir" -type f -exec sh -c '
for f do
echo "<$f>"
done
' sh {} +
या, अगर जरूरत है तो एक चयन (चयन बकवास का हिस्सा है, श नहीं):
$ find "$dir" -type f -exec bash -c '
select f; do echo "<$f>"; break; done ' bash {} +
1) deep/inside/a/dir/file name
2) deep/inside/a/dir/zz last file
3) deep/inside/a/dir/file with a
newline
4) deep/inside/a/dir/directory/file name
5) deep/inside/a/dir/directory/zz last file
6) deep/inside/a/dir/directory/file with a
newline
7) deep/inside/a/dir/directory/file
8) deep/inside/a/dir/file
#? 3
<deep/inside/a/dir/file with a
newline>
[१] यह वृक्ष (\ ०१२ नए हैं):
$ tree
.
└── deep
└── inside
└── a
└── dir
├── directory
│ ├── file
│ ├── file name
│ └── file with a \012newline
├── file
├── file name
├── otherfile
├── with a\012newline
└── zz last file
इस दो कमांड के साथ बनाया जा सकता है:
$ mkdir -p deep/inside/a/dir/directory/
$ touch deep/inside/a/dir/{,directory/}{file{,\ {name,with\ a$'\n'newline}},zz\ last\ file}