私はマークダウンで学生のためのクイズを書いています。テストの1つは次のとおりです。
% QUESTION
Who played drums for The Beatles?
(X) Ringo
( ) John
( ) Paul
( ) George
% QUESTION
What is the first line of MOBY DICK?
(X) Call me Ishmael.
( ) foo
( ) bar
( ) spam
( ) eggs
私はこのすべての選択肢オプションをランダムに選択したいと思います。だからシェルスクリプトが必要だと思います。
- (X)または()で始まる連続した行ブロックをすべて見つけます。
- これらの各行ブロックをスクランブルします。
可能ですか?私はこれを知り、shuf
テキストsort -R
行をランダムに選択しますが、これらのオプションブロックを分離する方法がわかりません。
答え1
AWKを使用:
BEGIN {
srand()
answers[1] = ""
delete answers[1]
}
function outputanswers(answers, len, i) {
len = length(answers)
while (length(answers) > 0) {
i = int(rand() * len + 1)
if (answers[i]) {
print answers[i]
}
delete answers[i]
}
}
/^$/ {
outputanswers(answers)
print
}
/^[^(]/
/^\(/ {
answers[length(answers) + 1] = $0
}
END { outputanswers(answers) }
答えを配列に蓄積しanswers
、必要に応じてその内容をランダムな順序で出力するように動作します。行が開かれているかっこで始まると、答えと見なされます(これはあなたの仕様を効果的に単純化することを願っています)。
答え2
パール方法:
perl -00 -M"List::Util qw/shuffle/" -lpe 'if(/^\(/){$_=join "\n",shuffle split(/\n/); }' file
コメントスクリプトと同じ:
#!/usr/bin/env perl
## Import the shuffle function from the List::Util module.
## This is done by the -M in the one-liner .
use List::Util qw/shuffle/;
## Enable paragraph mode, where each input record is a paragraph.
## This is equivalent to -00 in the one-liner.
$/ = "";
## set output record separator (done by -l when after -00)
$\ = "\n\n";
## Read each record of standard input into the special variable $_.
## -p in the one-liner adds a similar implicit loop around the code
## given to -e.
while (<>) {
## strip trailing newlines (done by -l in the one-liner)
chomp;
## If this record starts with a parenthesis
if(/^\(/){
## Split the record (here, the entire paragraph, the whole section
## until the next sequence of one or more empty lines) on newline
## characters and save in the array @lines. In the one-liner, I skipped
## creating this temporary array and joined the split directly
@lines = split(/\n/);
## Set the special variable $_ to hold the shuffled contents of
## the @lines array, now connected with newline characters again.
$_ = join "\n",shuffle @lines
}
## Print whatever is in the $_ variable. That's the additional thing
## -p does compared to -n.
print
}
そして楽しいことに、ここに少し短いバージョンがあります。
perl -MList::Util=shuffle -00lpe'$_=join"\n",shuffle split/\n/ if/^\(/' file
答え3
perl:
perl -F'\n' -MList::Util=shuffle -pal -00e '$"=$\;
$_ = "@{[/^\([X ]\)/ ? shuffle(@F) : @F]}"
. ($", $,)[eof];
' file
- 短絡モード -00 および自動分割 -a で newline-F'\n' に対して para を呼び出すと、フィールドは 0 インデックス配列 @F に格納されます。
- List::Util モジュール -M をロードし、ここからシャッフル機能をインポートします。
- (X)または()で始まる段落の場合はフィールドを再配置しますが、他の段落の場合は再配置しません。
GNU sed
sed -ne '
/^([X ])/!{p;d;} ;# just print noninteresting lines
:loop
H;$bshfl # accumulate the interesting lines in hold space
n
//bloop
:shfl
x;s/.// ;# retrieve hold n strip leading newline
s/.*/printf %s\\n "&" | shuf/ep ;# shuffle
z;x;/^([X ])/!s/^/\n/;D ;# null hold n loop back for more
' file
出力:現在の実行から開始
% QUESTION
Who played drums for The Beatles?
( ) John
( ) Georgen
( ) Paul
(X) Ringo
% QUESTION
What is the first line of MOBY DICK?
( ) eggsn
(X) Call me Ishmael.
( ) bar
( ) spam
( ) foo
答え4
混ぜたい行をパイプでつなぎshuf
、残りはそのまま印刷してください。
$ awk '/^\(/{print | "shuf"; next} !NF{close("shuf")} 1' file
% QUESTION
Who played drums for The Beatles?
( ) John
( ) Paul
(X) Ringo
( ) George
% QUESTION
What is the first line of MOBY DICK?
(X) Call me Ishmael.
( ) foo
( ) spam
( ) eggs
( ) bar