![쉘 스크립트가 동일한 정규식과 일치하는 모든 연속 행 그룹을 찾아서 섞을 수 있습니까?](https://linux55.com/image/186017/%EC%89%98%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EA%B0%80%20%EB%8F%99%EC%9D%BC%ED%95%9C%20%EC%A0%95%EA%B7%9C%EC%8B%9D%EA%B3%BC%20%EC%9D%BC%EC%B9%98%ED%95%98%EB%8A%94%20%EB%AA%A8%EB%93%A0%20%EC%97%B0%EC%86%8D%20%ED%96%89%20%EA%B7%B8%EB%A3%B9%EC%9D%84%20%EC%B0%BE%EC%95%84%EC%84%9C%20%EC%84%9E%EC%9D%84%20%EC%88%98%20%EC%9E%88%EC%8A%B5%EB%8B%88%EA%B9%8C%3F.png)
저는 마크다운으로 학생들을 위한 퀴즈를 작성하고 있습니다. 테스트 중 하나는 다음과 같습니다.
% 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