यूनिक्स कमांड लाइन में फ़ाइल से यादृच्छिक रेखा पढ़ने का एक आसान तरीका क्या है?
यूनिक्स कमांड लाइन में फ़ाइल से यादृच्छिक रेखा पढ़ने का एक आसान तरीका क्या है?
जवाबों:
आप उपयोग कर सकते हैं shuf
:
shuf -n 1 $FILE
एक उपयोगिता भी कहा जाता है rl
। डेबियन में यह randomize-lines
पैकेज में वही होता है जो आप चाहते हैं, हालांकि सभी डिस्ट्रो में उपलब्ध नहीं है। अपने होम पेज पर यह वास्तव में shuf
बदले के उपयोग की सिफारिश करता है (जो तब नहीं था जब इसे बनाया गया था, मुझे विश्वास है)। shuf
GNU कोरुटिल्स का हिस्सा है, rl
नहीं है।
rl -c 1 $FILE
shuf
टिप के लिए धन्यवाद , यह फेडोरा में बनाया गया है।
sort -R
निश्चित रूप से एक बहुत प्रतीक्षा करने जा रहा है अगर बहुत बड़ी फ़ाइलों के साथ काम कर रहा है - 80kk लाइनें -, जबकि, shuf -n
तुरंत काम करता है।
coreutils
Homebrew से इंस्टॉल करके OS X पर shuf कर सकते हैं । के gshuf
बजाय बुलाया जा सकता है shuf
।
randomize-lines
ओएस एक्स बायbrew install randomize-lines; rl -c 1 $FILE
shuf
का हिस्सा है और इसलिए आवश्यक रूप से * BSD सिस्टम (या Mac) पर उपलब्ध (डिफ़ॉल्ट रूप से) उपलब्ध नहीं होगा। @ Tracker1 का पर्ल वन-लाइनर अधिक पोर्टेबल है (और मेरे परीक्षणों से, थोड़ा तेज है)।
एक अन्य विकल्प:
head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1
(${RANDOM} << 15) + ${RANDOM}
। यह पूर्वाग्रह को काफी कम करता है और इसे 1 बिलियन लाइनों तक की फ़ाइलों के लिए काम करने की अनुमति देता है।
+
और परिभाषा के अनुसार 0..32767 |
से समान हैं ${RANDOM}
।
sort --random-sort $FILE | head -n 1
(मैं ऊपर भी बेहतर shuf दृष्टिकोण पसंद है - मैं भी नहीं जानता था कि अस्तित्व में है और मैं अपने दम पर कभी नहीं पाया है कि उपकरण)
sort
मेरे सिस्टम में से किसी पर काम नहीं करना चाहिए (CentOS 5.5, Mac OS 10.7.2)। इसके अलावा, बिल्ली का बेकार उपयोग, कम किया जा सकता हैsort --random-sort < $FILE | head -n 1
sort -R <<< $'1\n1\n2' | head -1
1 और 2 की वापसी की संभावना है, क्योंकि sort -R
डुप्लिकेट लाइनें एक साथ होती हैं। वही लागू होता है sort -Ru
, क्योंकि यह डुप्लिकेट लाइनों को हटा देता है।
sort
पाइप करने से पहले इसमें फेरबदल करने की आवश्यकता होती है head
। shuf
फ़ाइल से यादृच्छिक रेखाओं का चयन करता है, इसके बजाय और मेरे लिए बहुत तेज है।
sort --random-sort $FILE | head
तो यह सबसे अच्छा होगा, क्योंकि यह सीधे फ़ाइल को एक्सेस करने की अनुमति देता है, संभवतः कुशल समानांतर छँटाई को सक्षम करता है
--random-sort
और -R
विकल्पों जीएनयू प्रकार के लिए विशिष्ट हैं (ताकि वे बीएसडी या मैक ओएस के साथ काम नहीं करेगा sort
)। GNU सॉर्ट ने उन झंडों को 2005 में सीखा ताकि आपको GNU कोरुटिल्स 6.0 या नए (जैसे CentOS 6) की आवश्यकता हो।
यह सरल है।
cat file.txt | shuf -n 1
दी यह केवल अपने दम पर "shuf -n 1 file.txt" की तुलना में एक धीमी गति है।
-n 1
1 पंक्ति को निर्दिष्ट करता है, और आप इसे 1 से अधिक में बदल सकते हैं। shuf
अन्य चीजों के लिए भी इस्तेमाल किया जा सकता है; मैंने अभी-अभी पाइप किया ps aux
और इसके grep
साथ बेतरतीब ढंग से एक नाम से मेल खाते प्रक्रियाओं को मार डाला।
perlfaq5: मैं किसी फ़ाइल से यादृच्छिक रेखा कैसे चुनूं? यहाँ कैमल बुक से एक जलाशय-नमूना एल्गोरिथ्म है:
perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' file
इसमें पूरी फाइल को पढ़ने के स्थान पर एक महत्वपूर्ण लाभ है। आप डोनाल्ड ई। नुथ द्वारा, द आर्ट ऑफ़ कंप्यूटर प्रोग्रामिंग, वॉल्यूम 2, धारा 3.4.2 में इस पद्धति का प्रमाण पा सकते हैं।
shuf
। पर्ल कोड बहुत थोड़ा तेज है (उपयोगकर्ता समय के अनुसार 8% तेज, सिस्टम समय के अनुसार 24% तेज), हालांकि वास्तविक रूप से मैंने पाया है कि पर्ल कोड "कम यादृच्छिक" है (मैंने इसका उपयोग करके एक ज्यूकबॉक्स लिखा है)।
shuf
मेमोरी में पूरे इनपुट फ़ाइल को संग्रहीत करता है , जो एक भयानक विचार है, जबकि यह कोड केवल एक पंक्ति को संग्रहीत करता है, इसलिए इस कोड की सीमा INT_MAX की एक पंक्ति गणना है (2 ^ 31 या 2 ^ 63 आपके आधार पर आर्क), इसकी किसी भी चयनित संभावित रेखा को मानकर स्मृति में फिट बैठता है।
बैश स्क्रिप्ट का उपयोग करना:
#!/bin/bash
# replace with file to read
FILE=tmp.txt
# count number of lines
NUM=$(wc - l < ${FILE})
# generate random number in range 0-NUM
let X=${RANDOM} % ${NUM} + 1
# extract X-th line
sed -n ${X}p ${FILE}
सिंगल बैश लाइन:
sed -n $((1+$RANDOM%`wc -l test.txt | cut -f 1 -d ' '`))p test.txt
थोड़ा समस्या: डुप्लिकेट फ़ाइल नाम।
wc -l < test.txt
पाइप करने से बचा जाता है cut
।
यहाँ एक सरल पायथन स्क्रिप्ट है जो काम करेगी:
import random, sys
lines = open(sys.argv[1]).readlines()
print(lines[random.randrange(len(lines))])
उपयोग:
python randline.py file_to_get_random_line_from
import random, sys lines = open(sys.argv[1]).readlines()
i for रेंज (len (लाइनें)): rand = random.randint (0, len (लाइनें) -1) प्रिंट लाइन्स। Pop (रैंड),
len(lines)
जन्म दे सकता है। आप उपयोग कर सकते हैं print(random.choice(list(open(sys.argv[1]))))
। स्मृति कुशल जलाशय नमूना एल्गोरिथ्म भी है ।
' Awk ' का उपयोग करने का दूसरा तरीका
awk NR==$((${RANDOM} % `wc -l < file.name` + 1)) file.name
wc
लाइन की गिनती प्राप्त करने के लिए फ़ाइल ( ) को पढ़ना चाहिए, फिर awk
दिए गए यादृच्छिक लाइन नंबर की सामग्री को प्राप्त करने के लिए फ़ाइल को फिर से ( ) का हिस्सा पढ़ना होगा । रैंडम नंबर प्राप्त करने की तुलना में I / O कहीं अधिक महंगा होगा। मेरा कोड केवल एक बार फाइल पढ़ता है। Awk के साथ मुद्दा rand()
यह है कि यह सेकंड पर आधारित है, इसलिए यदि आप इसे बहुत तेजी से चलाते हैं तो आपको डुप्लिकेट मिलेंगे।
एक समाधान जो MacOSX पर भी काम करता है, और लिनक्स (?) पर भी काम करना चाहिए:
N=5
awk 'NR==FNR {lineN[$1]; next}(FNR in lineN)' <(jot -r $N 1 $(wc -l < $file)) $file
कहाँ पे:
N
आप चाहते हैं यादृच्छिक लाइनों की संख्या है
NR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2
-> में लिखी लाइन नंबर को सेव करें file1
और फिर संबंधित लाइन को प्रिंट करेंfile2
jot -r $N 1 $(wc -l < $file)
-> N
संख्या को यादृच्छिक रूप से ( -r
) के (1, number_of_line_in_file)
साथ सीमा में ड्रा करें jot
। प्रक्रिया प्रतिस्थापन <()
इसे दुभाषिया के लिए एक फ़ाइल की तरह बना देगा, इसलिए file1
पिछले उदाहरण में।#!/bin/bash
IFS=$'\n' wordsArray=($(<$1))
numWords=${#wordsArray[@]}
sizeOfNumWords=${#numWords}
while [ True ]
do
for ((i=0; i<$sizeOfNumWords; i++))
do
let ranNumArray[$i]=$(( ( $RANDOM % 10 ) + 1 ))-1
ranNumStr="$ranNumStr${ranNumArray[$i]}"
done
if [ $ranNumStr -le $numWords ]
then
break
fi
ranNumStr=""
done
noLeadZeroStr=$((10#$ranNumStr))
echo ${wordsArray[$noLeadZeroStr]}
यहाँ मैं क्या खोज रहा हूँ क्योंकि मेरा मैक ओएस सभी आसान उत्तरों का उपयोग नहीं करता है। मैंने एक संख्या उत्पन्न करने के लिए jot कमांड का उपयोग किया है क्योंकि $ RANDOM चर समाधान मेरे परीक्षण में बहुत यादृच्छिक नहीं लगते हैं। अपने समाधान का परीक्षण करते समय मेरे पास आउटपुट में प्रदान किए गए समाधानों में एक विस्तृत विचरण था।
RANDOM1=`jot -r 1 1 235886`
#range of jot ( 1 235886 ) found from earlier wc -w /usr/share/dict/web2
echo $RANDOM1
head -n $RANDOM1 /usr/share/dict/web2 | tail -n 1
चर की गूंज उत्पन्न यादृच्छिक संख्या का एक दृश्य प्राप्त करना है।
केवल वेनिला sed और awk का उपयोग करना, और $ RANDOM का उपयोग किए बिना, एक सरल, अंतरिक्ष-कुशल और यथोचित उपवास "वन-लाइनर" के लिए एक लाइन छद्म-यादृच्छिक रूप से FILENAME नामक फ़ाइल से चयन करने के लिए निम्नानुसार है:
sed -n $(awk 'END {srand(); r=rand()*NR; if (r<NR) {sub(/\..*/,"",r); r++;}; print r}' FILENAME)p FILENAME
(यह तब भी काम करता है, जब FILENAME खाली हो, जिस स्थिति में कोई रेखा उत्सर्जित नहीं होती है।)
इस दृष्टिकोण का एक संभावित लाभ यह है कि यह केवल एक बार रैंड () कहता है।
जैसा कि @AdamKatz ने टिप्पणियों में बताया है, एक और संभावना प्रत्येक पंक्ति के लिए रैंड () को कॉल करने की होगी:
awk 'rand() * NR < 1 { line = $0 } END { print line }' FILENAME
(इंडक्शन के आधार पर शुद्धता का एक सरल प्रमाण दिया जा सकता है।)
rand()
"ज्यादातर awk कार्यान्वयन में, जिसमें gawk, रैंड () एक ही शुरुआती संख्या या बीज से संख्या उत्पन्न करना शुरू करता है, हर बार जब आप awk चलाते हैं।"
- https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html