쉘 스크립트가 동일한 정규식과 일치하는 모든 연속 행 그룹을 찾아서 섞을 수 있습니까?

쉘 스크립트가 동일한 정규식과 일치하는 모든 연속 행 그룹을 찾아서 섞을 수 있습니까?

저는 마크다운으로 학생들을 위한 퀴즈를 작성하고 있습니다. 테스트 중 하나는 다음과 같습니다.

% 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

나는 이 모든 객관식 옵션을 무작위로 선택하고 싶습니다. 그래서 쉘 스크립트가 필요하다고 생각합니다.

  1. (X) 또는 ( )로 시작하는 연속된 줄 블록을 모두 찾습니다.
  2. 이러한 각 행 블록을 스크램블합니다.

가능합니까? 나는 이것을 알고 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

관련 정보