टेक्स्ट फ़ाइल से यादृच्छिक रेखा कैसे प्रदर्शित करें?


26

मैं एक शेल स्क्रिप्ट लिखने की कोशिश कर रहा हूं। विचार पाठ फ़ाइल से यादृच्छिक पर एक एकल पंक्ति का चयन करना और इसे उबंटू डेस्कटॉप अधिसूचना के रूप में प्रदर्शित करना है।

लेकिन मैं चाहता हूं कि स्क्रिप्ट को निष्पादित करने के लिए हर बार अलग-अलग लाइनें चुनी जाएं। क्या ऐसा करने का कोई उपाय है? मुझे पूरी स्क्रिप्ट नहीं चाहिए। बस इतनी सी साधारण बात।


यह भी देखें: askubuntu.com/q/492572/256099
पंड्या

जवाबों:


40

आप shufफ़ाइल से यादृच्छिक लाइनों को प्रिंट करने के लिए उपयोगिता का उपयोग कर सकते हैं

$ shuf -n 1 filename

-n : प्रिंट करने के लिए लाइनों की संख्या

उदाहरण:

$ shuf -n 1 /etc/passwd

git:x:998:998:git daemon user:/:/bin/bash

$ shuf -n 2 /etc/passwd

avahi:x:84:84:avahi:/:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false

लेकिन इसका उपयोग करके, मुझे n का मान मैन्युअल रूप से सही बदलना होगा? मैं चाहता हूं कि यह शेल स्वचालित रूप से यादृच्छिक में एक और लाइन चुने। यादृच्छिक में होने की बिल्कुल जरूरत नहीं है। लेकिन कुछ और लाइन।
आनंदू एम दास

4
@AnanduMDas नहीं, आपको nप्रिंट करने के लिए लाइनों की संख्या को निरूपित नहीं करना है । (यानी आप केवल एक लाइन या दो लाइन चाहते हैं)। पंक्ति संख्या नहीं (अर्थात पहली पंक्ति दूसरी पंक्ति)।
अनीशप

@AnanduMDas: मैंने अपने उत्तर में कुछ उदाहरण जोड़े हैं। आशा है कि अब यह स्पष्ट है।
अनीशेप

1
धन्यवाद u इसकी स्पष्ट अब :) मुझे एक और एल्गोरिथ्म भी मिला, इसकी तरह, date +%Sएक चर x में वर्तमान समय (केवल दूसरा, द्वारा ) को स्टोर करें , और फिर टेक्स्ट फ़ाइल से कमांड headऔर tailकमांड का उपयोग करके उस xth लाइन का चयन करें । वैसे भी आपकी विधि अधिक आसान है। धन्यवाद
Anandu एम दास

+1: shufकोरयूटिल्स में है इसलिए यह डिफ़ॉल्ट रूप से उपलब्ध है। नोट: यह इनपुट फ़ाइल को मेमोरी में लोड करता है। एक कुशल एल्गोरिथ्म है जिसकी आवश्यकता नहीं है
6

13

आप sortफ़ाइल से रैंडम लाइन प्राप्त करने के लिए कमांड का भी उपयोग कर सकते हैं ।

sort -R filename | head -n1

नोट: इनपुट में डुप्लिकेट लाइनों की sort -Rतुलना में shuf -n1या अलग-अलग परिणाम उत्पन्न करता है select-random@ EliahKagan की टिप्पणी देखें ।
16:24

8

सिर्फ मनोरंजन के लिए, यहाँ एक है शुद्ध बैश समाधान जो का उपयोग नहीं करता shuf, sort, wc, sed, head, tailया किसी अन्य बाहरी उपकरण।

shufवैरिएंट पर एकमात्र लाभ यह है कि यह थोड़ा तेज है, क्योंकि यह शुद्ध बैश है। मेरी मशीन पर, 1000 लाइनों की एक फ़ाइल के लिए shufवेरिएंट में लगभग 0.1 सेकंड लगते हैं, जबकि निम्न स्क्रिप्ट में लगभग 0.01 सेकंड लगते हैं;) तो जबकि shufसबसे आसान और सबसे छोटा संस्करण है, यह तेज़ है।

सभी ईमानदारी में मैं अभी भी shufसमाधान के लिए जाऊंगा , जब तक कि उच्च दक्षता एक महत्वपूर्ण चिंता नहीं है।

#!/bin/bash

FILE=file.txt

# get line count for $FILE (simulate 'wc -l')
lc=0
while read -r line; do
 ((lc++))
done < $FILE

# get a random number between 1 and $lc
rnd=$RANDOM
let "rnd %= $lc"
((rnd++))

# traverse file and find line number $rnd
i=0
while read -r line; do
 ((i++))
 [ $i -eq $rnd ] && break
done < $FILE

# output random line
printf '%s\n' "$line"

@EliahKagan सुझाव और अच्छे अंक के लिए धन्यवाद। मैं मानता हूँ कि काफी कुछ कोने मामले हैं जिन्हें मैंने वास्तव में बहुत अधिक सोचा नहीं था। मैंने इसे वास्तव में इसके मज़े के लिए लिखा था। का उपयोग करना shufवैसे भी बहुत बेहतर है। यह सोचते हुए, मुझे विश्वास नहीं होता कि शुद्ध बैश वास्तव में उपयोग करने की तुलना में अधिक कुशल है shuf, जैसा कि मैंने पहले लिखा था। बाहरी उपकरण को फायर करने पर सबसे नित्य (स्थिर) ओवरहेड हो सकता है, लेकिन फिर यह व्याख्या किए गए बैश की तुलना में तेजी से चलेगा। तो shufनिश्चित रूप से बेहतर तराजू। तो
मान

GNU / Linux / Un * x में बहुत ही अच्छी तरह से सड़क-परीक्षण किए गए पहिए हैं, जिन्हें मैं फिर से आविष्कार नहीं करना चाहता, जब तक कि यह पूरी तरह से शैक्षणिक अभ्यास नहीं था। "शेल" का उपयोग बहुत कम मौजूदा भागों को इकट्ठा करने के लिए किया जाना था जो कि इनपुट (आउटपुट) और बहुत सारे ओ 'विकल्पों के माध्यम से विभिन्न तरीकों से इकट्ठा किए जा सकते हैं। कुछ भी बुरा रूप है, जब तक कि यह खेल के लिए नहीं है (उदाहरण के लिए, codegolf.stackexchange.com/tour ), जिस स्थिति में खेलते हैं ...!
माइकल

2
@michael_n हालांकि "शुद्ध बैश" तरीका मुख्य रूप से शिक्षण के लिए और अन्य कार्यों के लिए संशोधित करने के लिए उपयोगी है, यह वास्तविक "कार्यान्वयन के लिए एक अधिक उचित" है जितना कि यह लग सकता है। बैश व्यापक रूप से उपलब्ध है, लेकिन shufGNU Coreutils - विशिष्ट (जैसे, FreeBSD 10.0 में नहीं)। sort -Rपोर्टेबल है, लेकिन एक अलग (संबंधित) समस्या को हल करता है: कई लाइनों के रूप में दिखने वाले तार में केवल एक बार दिखने वाले लोगों के बराबर संभावना है। (बेशक, wcऔर अन्य उपयोगिताओं को अभी भी इस्तेमाल किया जा सकता है।) मुझे लगता है कि यहां मुख्य सीमा यह है कि यह 32768 वीं पंक्ति के बाद कभी भी कुछ नहीं उठाता है (और कुछ हद तक कम यादृच्छिक हो जाता है)।
एलिया कगन

2
Malte Skoruppa: मैं देख रहा हूँ कि आपने Bash PRNG प्रश्न को U & L में स्थानांतरित कर दिया है । ठंडा। संकेत: $((RANDOM<<15|RANDOM))0..2 ^ 30-1 में है। @JFSebastian यह shuf, sort -Rअधिक लगातार इनपुट की ओर नहीं है कि skews। के shuf -n 1स्थान पर रखें sort -R | head -n1और तुलना करें। (Btw 10 ^ 3 पुनरावृत्तियों 10 ^ 6 की तुलना में तेज है और अभी भी काफी अंतर दिखाने के लिए पर्याप्त है।) यह भी एक मोटा, अधिक दृश्य डेमो और यह दिखावा का एक सा दिखा यह बड़े आदानों पर काम करता है जहां सभी तार उच्च आवृत्ति हैं
एलिया कागन

1
@JFSebastian उस कमांड में, इनपुट dieharderसभी शून्य लगता है। यह मानते हुए कि यह मेरी ओर से केवल कुछ अजीब गलती नहीं है, यह निश्चित रूप से समझाएगा कि यह यादृच्छिक क्यों नहीं है! क्या आपको while echo $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 )); do :; done | perl -ne 'print pack "I>"' > outकुछ समय के लिए चलाने पर अच्छा दिखने वाला डेटा मिलता है और फिर outहेक्स एडिटर की सामग्री की जांच करते हैं ? (या यह देखें कि आपको और क्या पसंद है।) मुझे सभी शून्य मिलते हैं, और RANDOMअपराधी नहीं है: जब मुझे प्रतिस्थापित किया $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 ))जाता है 100, तो मुझे सभी शून्य मिलते हैं।
एलिया कगन

4

बोलो तुम्हारे पास फाइल है notifications.txt। यादृच्छिक जनरेटर की सीमा निर्धारित करने के लिए हमें कुल लाइनों की संख्या की गणना करने की आवश्यकता है:

$ cat notifications.txt | wc -l

वेरिएबल को लिखें:

$ LINES=$(cat notifications.txt | wc -l)

अब से संख्या उत्पन्न करने 0के लिए $LINEहम प्रयोग करेंगे RANDOMचर।

$ echo $[ $RANDOM % LINES]

इसे वेरिएबल पर लिखें:

$  R_LINE=$(($RANDOM % LINES))

अब हमें केवल इस पंक्ति संख्या को प्रिंट करने की आवश्यकता है:

$ sed -n "${R_LINE}p" notifications.txt

रैंडम के बारे में:

   RANDOM Each time this parameter is referenced, a random integer between
          0 and 32767 is generated.  The sequence of random numbers may be
          initialized by assigning a value to RANDOM.  If RANDOM is unset,
          it  loses  its  special  properties,  even if it is subsequently
          reset.

सुनिश्चित करें कि आपकी फ़ाइल में 32767 पंक्ति संख्याएँ कम हैं। देखें इस अगर आप बड़ा यादृच्छिक जनरेटर है कि बॉक्स से बाहर काम करता है की जरूरत है।

उदाहरण:

$ od -A n -t d -N 3 /dev/urandom | tr -d ' '

एक शैलीगत विकल्प (बैश):LINES=$(wc -l < file.txt); R_LINE=$((RANDOM % LINES)); sed -n "${R_LINE}p" file.txt
माइकल


उदाहरण के लिए, टेस्ट PRNG में ग्रे बिटमैप का उपयोग करते हुए अंतिम तस्वीर को देखें कि यह समझने के लिए कि % nयादृच्छिक संख्या पर लागू करना एक अच्छा विचार क्यों नहीं है ।
jfs

2

यहाँ एक पायथन स्क्रिप्ट है जो इनपुट फ़ाइलों या स्टड से एक यादृच्छिक रेखा का चयन करती है:

#!/usr/bin/env python
"""Usage: select-random [<file>]..."""
import random

def select_random(iterable, default=None, random=random):
    """Select a random element from iterable.

    Return default if iterable is empty.
    If iterable is a sequence then random.choice() is used for efficiency instead.
    If iterable is an iterator; it is exhausted.
    O(n)-time, O(1)-space algorithm.
    """
    try:
        return random.choice(iterable) # O(1) time and space
    except IndexError: # empty sequence
        return default
    except TypeError: # not a sequence
        return select_random_it(iter(iterable), default, random.randrange)

def select_random_it(iterator, default=None, randrange=random.randrange):
    """Return a random element from iterator.

    Return default if iterator is empty.
    iterator is exhausted.
    O(n)-time, O(1)-space algorithm.
    """
    # from /programming//a/1456750/4279
    # select 1st item with probability 100% (if input is one item, return it)
    # select 2nd item with probability 50% (or 50% the selection stays the 1st)
    # select 3rd item with probability 33.(3)%
    # select nth item with probability 1/n
    selection = default
    for i, item in enumerate(iterator, start=1):
        if randrange(i) == 0: # random [0..i)
            selection = item
    return selection

if __name__ == "__main__":
    import fileinput
    import sys

    random_line = select_random_it(fileinput.input(), '\n')
    sys.stdout.write(random_line)
    if not random_line.endswith('\n'):
        sys.stdout.write('\n') # always append newline at the end

एल्गोरिथ्म O (n) -टाइम, O (1) -space है। यह 32767 लाइनों से बड़ी फ़ाइलों के लिए काम करता है। यह इनपुट फ़ाइलों को मेमोरी में लोड नहीं करता है। यह प्रत्येक इनपुट लाइन को एक बार पढ़ता है अर्थात, आप इसमें मनमाने बड़े (लेकिन परिमित) सामग्री को पाइप कर सकते हैं। यहाँ एल्गोरिथ्म का स्पष्टीकरण दिया गया है


1

मैं उस काम से प्रभावित हूं जो माल्टे स्कॉरुप्पा और अन्य लोगों ने किया था, लेकिन यहां एक बहुत सरल "शुद्ध बैश" तरीका है:

IFS=$'\012'
# set field separator to newline only
lines=( $(<test5) )
# slurp entire file into an array
numlines=${#lines[@]}
# count the array elements
num=$(( $RANDOM$RANDOM$RANDOM % numlines ))
# get a (more-or-less) random number within the correct range
line=${lines[$num]}
# select the element corresponding to the random number
echo $line
# display it

जैसा कि कुछ ने कहा है, $ रैंडम यादृच्छिक नहीं है। हालाँकि, 32767 लाइनों की फ़ाइल आकार सीमा $ RANDOMs को एक साथ स्ट्रिंग करके दूर की जाती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.