我正在用 Markdown 语言为我的学生编写测验。其中一项测验可能如下所示:
% 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
我想随机化所有这些多项选择选项。所以,我想我需要一个 shell 脚本:
- 查找以 (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 方法:
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 和 autosplit -a 中调用换行符 -F'\n' 上的 para,字段存储在零索引数组 @F 中
- 加载 List::Util 模块 -M 并从中导入 shuffle 函数。
- 对于以 (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