কীভাবে "জেনারেটর" যেমন ND র্যান্ডম প্রয়োগ করবেন?


10

$RANDOMপ্রতিবার এটি অ্যাক্সেস করা হলে বিশেষ পরিবর্তনশীলটির একটি নতুন মান থাকে। এই ক্ষেত্রে, এটি কিছু ভাষায় পাওয়া "জেনারেটর" অবজেক্টগুলির স্মরণ করিয়ে দেয়।

এর মতো কিছু বাস্তবায়নের কোনও উপায় আছে কি zsh?

নামযুক্ত পাইপগুলি দিয়ে এটি করার চেষ্টা করেছি, তবে "জেনারেটর" প্রক্রিয়াটি না মেরে নিয়ন্ত্রিত উপায়ে ফিফো থেকে আইটেমগুলি বের করার কোনও উপায় আমি পাইনি। উদাহরণ স্বরূপ:

% mkfifo /tmp/ints
% (index=0
   while ( true )
   do
       echo $index
       index=$(( index + 1 ))
   done) > /tmp/ints &
[1] 16309
% head -1 /tmp/ints
0
[1]  + broken pipe  ( index=0 ; while ( true; ); do; echo $index; index=$(( ...

Zsh এ যেমন জেনারেটর-ধরণের অবজেক্টটি প্রয়োগ করার অন্য কোনও উপায় আছে কি?


সম্পাদনা: এটি কাজ করে না:

#!/usr/bin/env zsh

FIFO=/tmp/fifo-$$
mkfifo $FIFO
INDEX=0
while true; do echo $(( ++INDEX )) > $FIFO; done &
cat $FIFO

যদি আমি উপরেরটি কোনও স্ক্রিপ্টে রাখি এবং চালিত করি তবে আউটপুটটি খুব কমই প্রত্যাশিত একক লাইন থাকে

1

বরং এটি বেশ কয়েকটি পূর্ণসংখ্যার সমন্বয়ে গঠিত হয়; যেমন

1
2
3
4
5

উত্পাদিত রেখার সংখ্যা এক রান থেকে পরের পর্যন্ত পরিবর্তিত হয়।

সম্পাদনা 2: জিম্মিজ যেমন উল্লেখ করেছেন, পরিবর্তন echoকরার /bin/echoজন্য সমস্যাটি দেখাশোনা করে।

উত্তর:


10

ksh93সাধারণত এই ধরণের জিনিসটির জন্য ব্যবহার করা হয় এমন শাখা রয়েছে। এর মাধ্যমে zsh, আপনি গতিশীল নামযুক্ত ডিরেক্টরি বৈশিষ্ট্যটি হাইজ্যাক করতে পারেন :

উদাহরণস্বরূপ সংজ্ঞা দিন:

zsh_directory_name() {
  case $1 in
    (n)
      case $2 in
        (incr) reply=($((++incr)))
      esac
  esac
}

এবং তারপরে আপনি প্রতিবার ~[incr]ইনক্রিমেন্ট পেতে ব্যবহার করতে পারেন $incr:

$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3

আপনার পন্থা ব্যর্থ হয়েছে কারণ head -1 /tmp/ints, মাথাটি ফিফোটি খুলবে, একটি পূর্ণ বাফার পড়ে, একটি লাইন মুদ্রণ করে এবং তারপরে এটি বন্ধ করে দেয় । একবার বন্ধ হয়ে গেলে, লেখার শেষটি একটি ভাঙা পাইপ দেখায়।

পরিবর্তে, আপনি হয় করতে পারেন:

$ fifo=~/.generators/incr
$ (umask  077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ seq infinity > $fifo &
$ exec 3< $fifo
$ IFS= read -rneu3
1
$ IFS= read -rneu3
2

সেখানে আমরা পড়ার শেষটি এফডি 3 এ খোলা রেখেছি এবং readএকবারে একটি বাইট পড়ি, ঠিক এক লাইনে (নতুন লাইনের চরিত্র পর্যন্ত) পড়ার বিষয়ে নিশ্চিত হওয়ার জন্য কোনও পূর্ণ বাফার নয়।

অথবা আপনি করতে পারেন:

$ fifo=~/.generators/incr
$ (umask  077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ while true; do echo $((++incr)) > $fifo; done &
$ cat $fifo
1
$ cat $fifo
2

এই সময়, আমরা প্রতিটি মানের জন্য পাইপ ইনস্ট্যান্ট করি। এটি যে কোনও লাইন সংখ্যায় সংখ্যক তথ্য সম্বলিত ডেটা ফেরত দেয়।

যাইহোক, সেই ক্ষেত্রে, catফিফোটি খোলার সাথে echoসাথে লুপটি অবরুদ্ধ হয়ে যায়, তাই আরও echoকিছুটা চালানো যেতে পারে, সময়ের catসাথে সাথে বিষয়বস্তুটি পড়ে এবং পাইপটি বন্ধ করে দেয় (এরপরে echoএকটি নতুন পাইপ ইনস্ট্যান্ট করার ফলে )।

চারপাশের কাজটি হতে পারে কিছুটা বিলম্ব যুক্ত করা যেমন উদাহরণস্বরূপ echo@ জিম্মিজের পরামর্শ অনুসারে একটি বাহ্যিক চালানো বা কিছু যোগ করা sleep, তবে এটি এখনও খুব দৃust় হবে না, বা আপনি প্রতিটি নামকরণ করা পাইপ পুনরায় তৈরি করতে পারেন echo:

while 
  mkfifo $fifo &&
  echo $((++incr)) > $fifo &&
  rm -f $fifo
do : nothing
done &

এটি এখনও ছোট উইন্ডোজ ছেড়ে দেয় যেখানে পাইপটি অস্তিত্বহীন হয়ে থাকে ( unlink()সম্পন্ন rmএবং mknod()সম্পন্ন mkfifoহওয়াগুলির মধ্যে) catব্যর্থ হওয়ার কারণ এবং খুব সংক্ষিপ্ত উইন্ডো যেখানে পাইপটি ইনস্ট্যান্ট করা হয়েছে তবে কোনও প্রক্রিয়া আর কখনও এটি লিখবে না (এবং write()এবং এর মধ্যে) close()দ্বারা সম্পন্ন echo) ঘটাচ্ছে catকিছুই ফেরত দিতে, এবং সংক্ষিপ্ত কোথায় জানালা নামক নল এখনও বিদ্যমান কিন্তু কিছুই কি কখনো লেখার জন্য এটি খোলার হবে (মধ্যে close()দ্বারা সম্পন্ন echoএবং unlink()দ্বারা সম্পন্ন rm) যেখানে catস্তব্ধ হবে।

আপনি উইন্ডোজগুলির মধ্যে কিছুগুলি এর মতো করে মুছে ফেলতে পারেন:

fifo=~/.generators/incr
(
  umask  077
  mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo &&
  while
    mkfifo $fifo.new &&
    {
      mv $fifo.new $fifo &&
      echo $((++incr))
    } > $fifo
  do : nothing
  done
) &

এইভাবে, একমাত্র সমস্যাটি হ'ল যদি আপনি একই সাথে কয়েকটি বিড়াল চালান (আমাদের লেখার লুপটি লেখার জন্য এটি খোলার জন্য প্রস্তুত হওয়ার আগে তারা সমস্ত ফিফো খুলেন) তবে তারা echoআউটপুটটি ভাগ করবে ।

আমি বিশ্ব লিখনযোগ্য ডিরেক্টরিতে স্থির নাম, বিশ্ব পঠনযোগ্য ফিফোস (বা সেই বিষয়ে কোনও ফাইল) তৈরির বিরুদ্ধেও পরামর্শ দেব /tmpযতক্ষণ না এটি সিস্টেমের সমস্ত ব্যবহারকারীর সামনে উন্মুক্ত করা কোনও পরিষেবা।


ধন্যবাদ। আমি যদি ভুল না করি তবে আপনার দেওয়া শেষ রেসিপিটি সর্বদা কার্যকর হয় না। আমার সম্পাদনা দেখুন।
কেজো

1
@ কেজো চেষ্টা করুন command echoবা /bin/echoবিল্ট-ইন এর পরিবর্তে echo। এছাড়াও - আপনি এই কমান্ড একটু খাটো বিট করতে পারেন: repeat 999 /bin/echo $((++incr)) > /tmp/int &
জিম্মিজ

1
@ কেজো, সম্পাদনা দেখুন।
স্টাফেন চেজেলাস

4

আপনি যখন কোডটি কার্যকর করতে চান যখনই কোনও ভেরিয়েবলের মান পড়া হয়, আপনি নিজেরাই zsh এর ভিতরে এটি করতে পারবেন না। RANDOMপরিবর্তনশীল (অন্যান্য অনুরূপ বিশেষ ভেরিয়েবল মত) হার্ড কোডেড zsh সোর্স কোড রয়েছে। তবে আপনি সি তে একটি মডিউল লিখে একই জাতীয় বিশেষ ভেরিয়েবলগুলি সংজ্ঞায়িত করতে পারেন স্ট্যান্ডার্ড মডিউলগুলির অনেকগুলিই বিশেষ ভেরিয়েবলগুলি সংজ্ঞায়িত করে।

আপনি একটি জেনারেটর তৈরি করতে একটি কপ্রোসেস ব্যবহার করতে পারেন ।

coproc { i=0; while echo $i; do ((++i)); done }
for ((x=1; x<=3; x++)) { read -p n; echo $n; }

তবে এটি বেশ সীমাবদ্ধ কারণ আপনার কেবলমাত্র একটি কপোক্রসেস থাকতে পারে। ক্রমবর্ধমানভাবে একটি প্রক্রিয়া থেকে আউটপুট পেতে অন্য উপায় একটি প্রক্রিয়া বিকল্প থেকে পুনর্নির্দেশ ।

exec 3< <(i=0; while echo $i; do ((++i)); done)
for ((x=1; x<=3; x++)) { read n <&3; echo $n; }

নোট যে head -1এখানে কাজ করে না, কারণ এটি একটি পুরো বাফার পড়ে, এটি কী পছন্দ করে তা মুদ্রণ করে এবং প্রস্থান করে। পাইপ থেকে যে ডেটা পড়েছে তা এখনও পড়ে আছে; এটি পাইপের একটি অভ্যন্তরীণ সম্পত্তি (আপনি আবার ডেটা স্টাফ করতে পারবেন না)। readBuiltin একটি সময়, যা এটি যত তাড়াতাড়ি এটা প্রথম সম্পর্কে newline খুঁজে বের করে বন্ধ করতে পারবেন কিন্তু খুব ধীর এক বাইট পড়া এই সমস্যা এড়াতে (অবশ্যই যে বিষয়টি আপনি মাত্র কয়েক শত বাইট পড়ি নেই)।


2
Zsh এ এক সময় কেবলমাত্র একমাত্র কপ্রোসেস আছে? আমি অবাক - এটি প্রায়শই আমি এমন জায়গা দেখি না যেখানে বাশ আরও নমনীয় হয়। :)
চার্লস ডাফি

@ চার্লসডুফি, আপনার zsh তে একাধিক কপ্রেসেস থাকতে পারে । কপ্রোসেসগুলি খুব সম্প্রতি যুক্ত করা হয়েছে bash, সেই লিঙ্কে ব্যাশ বিভাগটি দেখুন।
স্টাফেন চেজেলাস

@ StéphaneChazelas আপনি কীভাবে zsh এ একাধিক কোপ্রোসেসের সাথে ইন্টারঅ্যাক্ট করবেন? ( coprocকপ্রেসেসস, আমি জেপিটি নয়)
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'

সেই লিঙ্কে বর্ণিত হিসাবে ksh এর সাথে একইভাবে। coproc cmd1; exec 3>&p 4<&p; coproc cmd2 3>&- 4<&-...
স্টাফেন চেজেলাস

1

আমি মনে করি আমি এটি কোনও প্রকারের সংকেত দিয়ে করব।

(   trap   "read zero </tmp/ints" PIPE
    while  kill -s PIPE -0
    do     i=$zero
           while echo $((i++))
           do :; done 2>/dev/null >/tmp/ints
    done
)&

এটা যাইহোক, আমার জন্য কাজ করে।


$ echo  15 >/tmp/ints; head -n 5 </tmp/ints
15
16
17
18
19
$ echo  75 >/tmp/ints; head -n 5 </tmp/ints
75
76
77
78
79

কেবলমাত্র সামান্য সম্পর্কিত নোটে, আমি অন্য দিনটি আবিষ্কার করেছি এমন কিছু অদ্ভুত বিষয়:

mkdir nums; cd nums
for n in 0 1 2 3 4 5 6 7
do  ln -s ./ "$n"; done
echo [0-3]/*/*

0/0/0 0/0/1 0/0/2 0/0/3 0/0/4 0/0/5 0/0/6 0/0/7 0/1/0 0/1/1 0/1/2 0/1/3 0/1/4 0/1/5 0/1/6 0/1/7 0/2/0 0/2/1 0/2/2 0/2/3 0/2/4 0/2/5 0/2/6 0/2/7 0/3/0 0/3/1 0/3/2 0/3/3 0/3/4 0/3/5 0/3/6 0/3/7 0/4/0 0/4/1 0/4/2 0/4/3 0/4/4 0/4/5 0/4/6 0/4/7 0/5/0 0/5/1 0/5/2 0/5/3 0/5/4 0/5/5 0/5/6 0/5/7 0/6/0 0/6/1 0/6/2 0/6/3 0/6/4 0/6/5 0/6/6 0/6/7 0/7/0 0/7/1 0/7/2 0/7/3 0/7/4 0/7/5 0/7/6 0/7/7 1/0/0 1/0/1 1/0/2 1/0/3 1/0/4 1/0/5 1/0/6 1/0/7 1/1/0 1/1/1 1/1/2 1/1/3 1/1/4 1/1/5 1/1/6 1/1/7 1/2/0 1/2/1 1/2/2 1/2/3 1/2/4 1/2/5 1/2/6 1/2/7 1/3/0 1/3/1 1/3/2 1/3/3 1/3/4 1/3/5 1/3/6 1/3/7 1/4/0 1/4/1 1/4/2 1/4/3 1/4/4 1/4/5 1/4/6 1/4/7 1/5/0 1/5/1 1/5/2 1/5/3 1/5/4 1/5/5 1/5/6 1/5/7 1/6/0 1/6/1 1/6/2 1/6/3 1/6/4 1/6/5 1/6/6 1/6/7 1/7/0 1/7/1 1/7/2 1/7/3 1/7/4 1/7/5 1/7/6 1/7/7 2/0/0 2/0/1 2/0/2 2/0/3 2/0/4 2/0/5 2/0/6 2/0/7 2/1/0 2/1/1 2/1/2 2/1/3 2/1/4 2/1/5 2/1/6 2/1/7 2/2/0 2/2/1 2/2/2 2/2/3 2/2/4 2/2/5 2/2/6 2/2/7 2/3/0 2/3/1 2/3/2 2/3/3 2/3/4 2/3/5 2/3/6 2/3/7 2/4/0 2/4/1 2/4/2 2/4/3 2/4/4 2/4/5 2/4/6 2/4/7 2/5/0 2/5/1 2/5/2 2/5/3 2/5/4 2/5/5 2/5/6 2/5/7 2/6/0 2/6/1 2/6/2 2/6/3 2/6/4 2/6/5 2/6/6 2/6/7 2/7/0 2/7/1 2/7/2 2/7/3 2/7/4 2/7/5 2/7/6 2/7/7 3/0/0 3/0/1 3/0/2 3/0/3 3/0/4 3/0/5 3/0/6 3/0/7 3/1/0 3/1/1 3/1/2 3/1/3 3/1/4 3/1/5 3/1/6 3/1/7 3/2/0 3/2/1 3/2/2 3/2/3 3/2/4 3/2/5 3/2/6 3/2/7 3/3/0 3/3/1 3/3/2 3/3/3 3/3/4 3/3/5 3/3/6 3/3/7 3/4/0 3/4/1 3/4/2 3/4/3 3/4/4 3/4/5 3/4/6 3/4/7 3/5/0 3/5/1 3/5/2 3/5/3 3/5/4 3/5/5 3/5/6 3/5/7 3/6/0 3/6/1 3/6/2 3/6/3 3/6/4 3/6/5 3/6/6 3/6/7 3/7/0 3/7/1 3/7/2 3/7/3 3/7/4 3/7/5 3/7/6 3/7/7

এটি খুব অবাক হয়:

rm *
for a in  a b c d e f g h \
          i j k l m n o p \
          q r s t u v x y z
do 
    ln -s ./ "$a"
done
for a in *
do  echo "$a"/["$a"-z]
done

a/a a/b a/c a/d a/e a/f a/g a/h a/i a/j a/k a/l a/m a/n a/o a/p a/q a/r a/s a/t a/u a/v a/x a/y a/z
b/b b/c b/d b/e b/f b/g b/h b/i b/j b/k b/l b/m b/n b/o b/p b/q b/r b/s b/t b/u b/v b/x b/y b/z
c/c c/d c/e c/f c/g c/h c/i c/j c/k c/l c/m c/n c/o c/p c/q c/r c/s c/t c/u c/v c/x c/y c/z
d/d d/e d/f d/g d/h d/i d/j d/k d/l d/m d/n d/o d/p d/q d/r d/s d/t d/u d/v d/x d/y d/z
e/e e/f e/g e/h e/i e/j e/k e/l e/m e/n e/o e/p e/q e/r e/s e/t e/u e/v e/x e/y e/z
f/f f/g f/h f/i f/j f/k f/l f/m f/n f/o f/p f/q f/r f/s f/t f/u f/v f/x f/y f/z
g/g g/h g/i g/j g/k g/l g/m g/n g/o g/p g/q g/r g/s g/t g/u g/v g/x g/y g/z
h/h h/i h/j h/k h/l h/m h/n h/o h/p h/q h/r h/s h/t h/u h/v h/x h/y h/z
i/i i/j i/k i/l i/m i/n i/o i/p i/q i/r i/s i/t i/u i/v i/x i/y i/z
j/j j/k j/l j/m j/n j/o j/p j/q j/r j/s j/t j/u j/v j/x j/y j/z
k/k k/l k/m k/n k/o k/p k/q k/r k/s k/t k/u k/v k/x k/y k/z
l/l l/m l/n l/o l/p l/q l/r l/s l/t l/u l/v l/x l/y l/z
m/m m/n m/o m/p m/q m/r m/s m/t m/u m/v m/x m/y m/z
n/n n/o n/p n/q n/r n/s n/t n/u n/v n/x n/y n/z
o/o o/p o/q o/r o/s o/t o/u o/v o/x o/y o/z
p/p p/q p/r p/s p/t p/u p/v p/x p/y p/z
q/q q/r q/s q/t q/u q/v q/x q/y q/z
r/r r/s r/t r/u r/v r/x r/y r/z
s/s s/t s/u s/v s/x s/y s/z
t/t t/u t/v t/x t/y t/z
u/u u/v u/x u/y u/z
v/v v/x v/y v/z
x/x x/y x/z
y/y y/z
z/z

এতে কী অদ্ভুত ?
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস - লিঙ্কগুলি স্ব-পুনরাবৃত্তি হবে বলে মনে হয়েছিল কেবল অদ্ভুত। এবং তাই সহজে। আমি ভেবেছিলাম এটা অদ্ভুত। এবং শীতল। আমি আরও ভেবেছিলাম যে এখানে এক ধরণের গভীরতার পুনরাবৃত্তি সীমা থাকার কথা ছিল - শেলটি এটি ট্রিগার করবে বলে মনে হয় - বা এটি কি আসলে একক পথে 40 টি লিঙ্ক করা দরকার?
মাইক্রজারভ


@ স্টাফেনচাজেলাস - এটি বেশ ভাল। তবে কি bashএর আচরণ বদলেছে? আমি মনে করি pwdযাচাই না করা এবং কেবলমাত্র উল্লেখ করার বিষয়ে বিবৃতিটি $PWDভুল। mkdir /tmp/dir; cd $_; PS4='$OLDPWD, $PWD + '; set -x; OLDPWD=$OLDPWD PWD=$PWD command eval ' cd ..; cd ..; cd ~; pwd'; pwd; cd .; pwdআমি আপনাকে বোঝাতে চাইছি। এটি এমন সমস্যা যা আমাকে ডাব্লু / এই ns()জিনিসটি বাগিয়ে দিয়েছে ।
মাইক্রজারভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.