मैं एक पाठ फ़ाइल की लाइनों को बेतरतीब ढंग से फेरबदल करना और एक नई फ़ाइल बनाना चाहता हूं। फ़ाइल में कई हज़ारों लाइनें हो सकती हैं।
मुझे लगता है कि कैसे कर सकते हैं के साथ cat
, awk
, cut
, आदि?
मैं एक पाठ फ़ाइल की लाइनों को बेतरतीब ढंग से फेरबदल करना और एक नई फ़ाइल बनाना चाहता हूं। फ़ाइल में कई हज़ारों लाइनें हो सकती हैं।
मुझे लगता है कि कैसे कर सकते हैं के साथ cat
, awk
, cut
, आदि?
जवाबों:
आप उपयोग कर सकते हैं shuf
। कम से कम कुछ प्रणालियों में (POSIX में नहीं दिखता है)।
जैसा कि jleedev ने बताया: sort -R
एक विकल्प भी हो सकता है। कम से कम कुछ प्रणालियों पर; ठीक है, तुम तस्वीर लो। यह बताया गया है कि sort -R
वास्तव में फेरबदल नहीं करता है, बल्कि उनके हैश मूल्य के अनुसार आइटम सॉर्ट करता है।
[संपादक का ध्यान दें: sort -R
लगभग फेरबदल, सिवाय इसके कि डुप्लिकेट लाइनें / सॉर्ट कुंजियाँ हमेशा एक दूसरे के बगल में समाप्त होती हैं । दूसरे शब्दों में: केवल अद्वितीय इनपुट लाइनों / कुंजियों के साथ यह एक सही फेरबदल है। हालांकि यह सच है कि आउटपुट ऑर्डर हैश मानों द्वारा निर्धारित किया जाता है , यादृच्छिकता एक यादृच्छिक हैश फ़ंक्शन चुनने से आती है - मैनुअल देखें ।]
shuf
और sort -R
थोड़ा अलग है, क्योंकि sort -R
बेतरतीब ढंग से तत्वों को उनमें से हैश के अनुसार आदेश देता है, जो sort -R
कि दोहराए गए तत्वों को एक साथ रखेगा, जबकि shuf
सभी तत्वों को यादृच्छिक रूप से फेरबदल करता है।
brew install coreutils
फिर, का उपयोग करें gshuf ...
: (:
sort -R
और shuf
इसे पूरी तरह से अलग रूप में देखा जाना चाहिए। sort -R
नियतात्मक है। यदि आप इसे एक ही इनपुट पर दो बार अलग-अलग समय पर कॉल करते हैं तो आपको एक ही उत्तर मिलेगा। shuf
दूसरी ओर, यादृच्छिक उत्पादन का उत्पादन करता है, इसलिए यह सबसे अधिक संभावना एक ही इनपुट पर अलग-अलग आउटपुट देगा।
पर्ल वन-लाइनर मैक्सिम के समाधान का एक सरल संस्करण होगा
perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
\n
; हाँ, यह \n
मौजूद होना चाहिए - और यह आम तौर पर है - अन्यथा आपको वह मिलेगा जो आप वर्णन करते हैं।
<STDIN>
साथ बदलने का सुझाव देता हूं <>
, इसलिए समाधान फाइलों से इनपुट के साथ भी काम करता है।
यह उत्तर निम्नलिखित तरीकों से कई महान मौजूदा उत्तरों का अनुपालन करता है:
मौजूदा उत्तर लचीले शेल फ़ंक्शंस में पैक किए गए हैं :
stdin
इनपुट लेते हैं , बल्कि वैकल्पिक रूप से तर्कों को भी फिल्माते हैंSIGPIPE
(निकास कोड के साथ शांत समाप्ति 141
), जैसा कि नीरवता को तोड़ने के लिए किया गया था। फंक्शन आउटपुट को पाइप से बंद करते समय यह महत्वपूर्ण है जो जल्दी बंद हो जाता है, जैसे कि पाइपिंग करते समय head
।एक प्रदर्शन तुलना की जाती है।
awk
, sort
औरcut
, से अनुकूलित ओ पी के अपने जवाब :shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "$@" |
sort -k1,1n | cut -d ' ' -f2-; }
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write("".join(lines))
' "$@"; }
इस फ़ंक्शन के विंडोज संस्करण के लिए नीचे अनुभाग देखें ।
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
puts ARGF.readlines.shuffle' "$@"; }
प्रदर्शन की तुलना:
नोट: ये नंबर 3.2 गीगाहर्ट्ज इंटेल कोर i5 और एक फ्यूजन ड्राइव के साथ 2012 के बाद वाले iMac पर प्राप्त हुए थे, OSX 10.3.3 पर चल रहे थे। जबकि OS का उपयोग OS, मशीन स्पेक्स, awk
कार्यान्वयन के साथ अलग-अलग होगा (उदाहरण के लिए, awk
OSX पर उपयोग किया जाने वाला BSD संस्करण आमतौर पर GNU awk
और विशेष रूप से धीमा होता है mawk
), यह सापेक्ष प्रदर्शन की एक सामान्य भावना प्रदान करता है ।
इनपुट फ़ाइल एक 1-मिलियन-लाइनों वाली फ़ाइल है जिसका उत्पादन किया गया है seq -f 'line %.0f' 1000000
।
टाइम्स को आरोही क्रम में सूचीबद्ध किया गया है (सबसे पहले):
shuf
0.090s
0.289s
0.589s
1.342s
पायथन 2.7.6 के साथ; 2.407s
(!) पायथन 3.4.2 के साथawk
+ sort
+cut
3.003s
बीएसडी के साथ awk
; 2.388s
जीएनयू awk
(4.1.1) के साथ; 1.811s
साथ mawk
(1.3.4);आगे की तुलना के लिए, समाधान ऊपर के कार्यों के रूप में पैक नहीं किए गए हैं:
sort -R
(डुप्लिकेट इनपुट लाइनों हैं, तो एक सही फेरबदल नहीं)
10.661s
- अधिक मेमोरी आवंटित करने से कोई फर्क नहीं पड़ता है24.229s
bash
छोरों + sort
32.593s
निष्कर्ष :
shuf
, यदि आप कर सकते हैं - यह अब तक का सबसे तेज है।awk
+ sort
+ cut
कॉम्बो का उपयोग अंतिम उपाय के रूप में करें ; कौन सा awk
कार्यान्वयन आप मामलों का उपयोग करते हैं ( mawk
यह जीएनयू की तुलना में तेज है awk
, बीएसडी awk
सबसे धीमा है)।sort -R
, bash
छोरों, और स्काला।पायथन सॉल्यूशन के विंडोज संस्करण (पायथन कोड समान है, सिवाय उद्धरण-चिह्नों में भिन्नता के और सिवाय संकेत-संबंधित कथनों को हटाने के, जो विंडोज पर समर्थित नहीं हैं):
$OutputEncoding
यदि आप पाइपलाइन के माध्यम से गैर-ASCII वर्ण भेजना चाहते हैं):# Call as `shuf someFile.txt` or `Get-Content someFile.txt | shuf`
function shuf {
$Input | python -c @'
import sys, random, fileinput;
lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write(''.join(lines))
'@ $args
}
ध्यान दें कि PowerShell अपने Get-Random
cmdlet के माध्यम से मूल रूप से फेरबदल कर सकता है (हालांकि प्रदर्शन एक समस्या हो सकती है); उदाहरण के लिए:
Get-Content someFile.txt | Get-Random -Count ([int]::MaxValue)
cmd.exe
(एक बैच फ़ाइल):shuf.cmd
उदाहरण के लिए फ़ाइल को सहेजें :
@echo off
python -c "import sys, random, fileinput; lines=[line for line in fileinput.input()]; random.shuffle(lines); sys.stdout.write(''.join(lines))" %*
python -c "import sys, random; lines = [x for x in sys.stdin.read().splitlines()] ; random.shuffle(lines); print(\"\n\".join([line for line in lines]));"
from signal import signal, SIGPIPE, SIG_DFL; signal(SIGPIPE, SIG_DFL);
मूल समाधान से छूटना पर्याप्त है, और फाइलनाम तर्कों को पारित करने में सक्षम होने के लचीलेपन को भी बरकरार रखता है - कुछ और बदलने की आवश्यकता नहीं है (उद्धरण के अलावा) - कृपया मेरे द्वारा जोड़े गए नए अनुभाग को देखें तल।
मैं एक छोटी पर्ल स्क्रिप्ट का उपयोग करता हूं, जिसे मैं "अनसॉर्ट" कहता हूं:
#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
मुझे एक NULL- सीमांकित संस्करण भी मिला है, जिसे "unsort0" कहा जाता है ... Find -print0 और इतने पर उपयोग के लिए आसान है।
पुनश्च: 'shuf' को भी वोट किया, मुझे नहीं पता था कि इन दिनों कोरुटील्स में था ... यदि आपके सिस्टम में 'shuf' नहीं है तो भी उपरोक्त उपयोगी हो सकता है।
<STDIN>
साथ <>
आदेश से इनपुट के साथ समाधान काम करने के लिए में फ़ाइलों को भी।
यहां एक पहली कोशिश है जो कोडर पर आसान है लेकिन सीपीयू पर कठिन है जो प्रत्येक पंक्ति के लिए एक यादृच्छिक संख्या को प्रस्तुत करता है, उन्हें सॉर्ट करता है और फिर प्रत्येक पंक्ति से यादृच्छिक संख्या को स्ट्रिप्स करता है। वास्तव में, लाइनों को यादृच्छिक रूप से हल किया जाता है:
cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
head myfile | awk ...
। फिर मैं इसे सिर्फ बिल्ली में बदल देता हूं; इसलिए इसे वहीं छोड़ दिया गया।
-k1 -n
सॉर्ट की आवश्यकता नहीं है , क्योंकि awk का आउटपुट rand()
0 और 1 के बीच का दशमलव है और क्योंकि यह सब मायने रखता है कि यह किसी भी तरह से फिर से व्यवस्थित हो जाता है। -k1
बाकी लाइन की अनदेखी करके इसे गति देने में मदद कर सकता है, हालांकि रैंड () का आउटपुट तुलनात्मक रूप से शॉर्ट-सर्किट के लिए अद्वितीय होना चाहिए।
cat filename |
(या < filename |
) यह याद रखें कि प्रत्येक एकल प्रोग्राम फ़ाइल इनपुट (या नहीं) लेता है।
यहाँ एक अजीब स्क्रिप्ट है
awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
while (1){
if (e==d) {break}
RANDOM = int(1 + rand() * d)
if ( RANDOM in lines ){
print lines[RANDOM]
delete lines[RANDOM]
++e
}
}
}' file
उत्पादन
$ cat file
1
2
3
4
5
6
7
8
9
10
$ ./shell.sh
7
5
10
9
6
8
2
1
3
4
awk
के साथ sort
और cut
। कई हजारों लाइन से अधिक के लिए यह बहुत फर्क नहीं करता है, लेकिन उच्च रेखा के साथ यह मायने रखता है (सीमा awk
कार्यान्वयन पर निर्भर करता है)। थोड़ा सा सरलीकरण लाइनों while (1){
और if (e==d) {break}
साथ बदलने के लिए होगा while (e<d)
।
अजगर के लिए एक लाइनर:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile
और मुद्रण के लिए सिर्फ एक यादृच्छिक लाइन:
python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile
लेकिन अजगर की कमियों के लिए इस पोस्ट को देखें random.shuffle()
। यह कई (2080 से अधिक) तत्वों के साथ अच्छी तरह से काम नहीं करेगा।
/dev/urandom
है। इसे पायथन से उपयोग करने के लिए random.SystemRandom().shuffle(L)
:।
.readLines()
रेखा के साथ रेखाएं वापस आती हैं ।
सरल awk- आधारित कार्य करेंगे:
shuffle() {
awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8-
}
उपयोग:
any_command | shuffle
यह लगभग किसी भी यूनिक्स पर काम करना चाहिए। लिनक्स, सोलारिस और एचपी-यूएक्स पर परीक्षण किया गया।
अपडेट करें:
ध्यान दें, कि अग्रणी शून्य ( %06d
) और rand()
गुणा यह उन प्रणालियों पर भी ठीक से काम करने के लिए बनाता है जहां sort
संख्या समझ में नहीं आती है। इसे लेक्सिकोग्राफिक ऑर्डर (उर्फ सामान्य स्ट्रिंग तुलना) के माध्यम से हल किया जा सकता है।
"$@"
, तो यह इनपुट के रूप में फाइलों के साथ भी काम करेगा । गुणा करने का कोई कारण नहीं है rand()
, क्योंकि sort -n
दशमलव अंशों को छांटने में सक्षम है। यह नियंत्रित करने के लिए एक अच्छा विचार है तथापि, awk
क्योंकि डिफ़ॉल्ट प्रारूप, साथ के उत्पादन प्रारूप, %.6g
, rand()
इच्छा उत्पादन में कभी-कभार संख्या घातीय संकेतन। जबकि 1 मिलियन लाइनों तक फेरबदल करना व्यवहार में यकीनन पर्याप्त है, परफॉरमेंस पेनल्टी का भुगतान किए बिना अधिक लाइनों का समर्थन करना आसान है; उदा %.17f
।
sort
दशमलव अंशों को संभालने में सक्षम होना चाहिए (यहां तक कि हजारों विभाजकों के साथ, जैसा कि मैंने अभी देखा है)।
रूबी FTW:
ls | ruby -e 'puts STDIN.readlines.shuffle'
puts ARGF.readlines.shuffle
, तो आप इसे स्टडिन इनपुट और फ़ाइल नाम तर्क दोनों के साथ काम कर सकते हैं।
ruby -e 'puts $<.sort_by{rand}'
- ARGF पहले से ही एक गणना योग्य है, इसलिए हम इसे यादृच्छिक मानों द्वारा क्रमबद्ध करके लाइनों को फेरबदल कर सकते हैं।
स्काइ के उत्तर के आधार पर पायथन के लिए एक लाइनर , लेकिन a) स्टीन लेता है, b) बीज के साथ परिणाम को दोहराने योग्य बनाता है, c) सभी लाइनों में से केवल 200 को निकालता है।
$ cat file | python -c "import random, sys;
random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
> 200lines.txt
एक सरल और सहज तरीका उपयोग करना होगा shuf
।
उदाहरण:
मान लें words.txt
:
the
an
linux
ubuntu
life
good
breeze
लाइनों को फेरबदल करने के लिए, करें:
$ shuf words.txt
जो मानक उत्पादन में फेरबदल लाइनों को फेंक देगा ; तो, आप इसे एक आउटपुट फ़ाइल की तरह पाइप कर सकते हैं:
$ shuf words.txt > shuffled_words.txt
एक ऐसा फेरबदल से उपज मिल सकती है:
breeze
the
linux
an
ubuntu
good
life
यह एक अजगर स्क्रिप्ट है जिसे मैंने अपने होम फ़ोल्डर में rand.py के रूप में सहेजा है:
#!/bin/python
import sys
import random
if __name__ == '__main__':
with open(sys.argv[1], 'r') as f:
flist = f.readlines()
random.shuffle(flist)
for line in flist:
print line.strip()
Mac OSX पर sort -R
और shuf
उपलब्ध नहीं हैं, इसलिए आप इसे अपने bash_profile में इस रूप में शामिल कर सकते हैं:
alias shuf='python rand.py'
अगर मेरी तरह तुम यहाँ shuf
macOS के लिए एक वैकल्पिक के लिए देखने के लिए आया था तो उपयोग करें randomize-lines
।
स्थापित करें randomize-lines
(होमब्रेव) पैकेज, जिसमें एक rl
कमांड है जिसकी कार्यक्षमता समान है shuf
।
brew install randomize-lines
Usage: rl [OPTION]... [FILE]...
Randomize the lines of a file (or stdin).
-c, --count=N select N lines from the file
-r, --reselect lines may be selected multiple times
-o, --output=FILE
send output to file
-d, --delimiter=DELIM
specify line delimiter (one character)
-0, --null set line delimiter to null character
(useful with find -print0)
-n, --line-number
print line number with output lines
-q, --quiet, --silent
do not output any errors or warnings
-h, --help display this help and exit
-V, --version output version information and exit
brew install coreutils
में shuf
बाइनरी प्रदान करता है gshuf
।
यदि आपने स्काला स्थापित किया है, तो इनपुट को फेरबदल करने के लिए यहां एक-लाइनर है:
ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
इस बैश फ़ंक्शन में न्यूनतम निर्भरता होती है (केवल सॉर्ट और बैश):
shuf() {
while read -r x;do
echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
echo $y
done
}
awk
देता है, लेकिन प्रदर्शन बड़े इनपुट के साथ एक समस्या होगी; एक ही $RANDOM
मूल्य का उपयोग सही ढंग से केवल 32,768 इनपुट लाइनों तक फेरबदल करता है; जब आप उस सीमा का विस्तार कर सकते हैं, तो यह शायद इसके लायक नहीं है: उदाहरण के लिए, मेरी मशीन पर, आपकी स्क्रिप्ट को 32,768 शॉर्ट इनपुट लाइनों पर चलाने में लगभग 1 सेकंड लगता है, जो कि लगभग 150 बार चलता shuf
है जब तक कि रनिंग लेता है, और लगभग 10-15 बार जब तक ओपी का खुद का awk
समाधान निकाला जाता है। यदि आप sort
मौजूद होने पर भरोसा कर सकते हैं , awk
तो वहां भी होना चाहिए।
विंडोज़ में आप अपने डेटा को बदलने में मदद करने के लिए इस बैच फ़ाइल को आज़मा सकते हैं। इसके अलावा , बैच कोड का उपयोग होता है
C:\> type list.txt | shuffle.bat > maclist_temp.txt
इस आदेश को जारी करने के बाद, maclist_temp.txt में लाइनों की यादृच्छिक सूची होगी।
उम्मीद है की यह मदद करेगा।
अभी तक उल्लेख नहीं किया गया है:
उपयोग unsort
। सिंटैक्स (कुछ प्लेलिस्ट उन्मुख):
unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
[--identity] [--filenames[=profile]] [--separator sep] [--concatenate]
[--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null]
[--linefeed] [file ...]
msort
लाइन से फेरबदल कर सकते हैं, लेकिन यह आमतौर पर ओवरकिल है:
seq 10 | msort -jq -b -l -n 1 -c r