bash의 변수에 중첩된 명령의 출력을 할당할 수 없습니다.

bash의 변수에 중첩된 명령의 출력을 할당할 수 없습니다.

파일에서 임의의 줄을 선택하는 다음 명령을 변수에 할당하려고 하는데 작동하지 않습니다.

givinv@87-109:~$ head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1
cower
givinv@87-109:~$

다음은 변수에 할당하려고 할 때 발생하는 오류입니다.

givinv@87-109:~$ VARIA=`head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1`
bash: command substitution: line 1: unexpected EOF while looking for matching `)'
bash: command substitution: line 2: syntax error: unexpected end of file
bash: command substitution: line 1: syntax error near unexpected token `)'
bash: command substitution: line 1: ` + 1)) file | tail -1'
-l: command not found
givinv@87-109:~$

동일한 for 루프를 시도했지만 작동하지 않았습니다.:

givinv@87-109:~$ for i in `head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1`;do echo $i ;done
bash: syntax error near unexpected token `<'
givinv@87-109:~$ 

답변1

이스케이프되지 않은 백틱을 중첩하려고 하기 때문에 작동하지 않습니다.

VARIA=`head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1`

head -$((${RANDOM} %실제로는 먼저 단일 명령으로 실행을 시도하는데, 이로 인해 두 가지 첫 번째 오류가 발생합니다.

$ VARIA=`head -$((${RANDOM} % `
bash: command substitution: line 1: unexpected EOF while looking for matching `)'
bash: command substitution: line 2: syntax error: unexpected end of file

그런 다음 실행을 시도합니다.

wc -l < file` + 1)) file | tail -1`

이는 + 1)) file | tail -1백틱 사이에서 평가를 시도하여 다음 오류가 발생함을 의미합니다.

$ wc -l < file` + 1)) file | tail -1`
bash: command substitution: line 1: syntax error near unexpected token `)'
bash: command substitution: line 1: ` + 1)) file | tail -1'

백틱을 이스케이프 처리하여 이 문제를 해결할 수 있습니다.

VARIA=`head -$((${RANDOM} % \`wc -l < file\` + 1)) file | tail -1`

그러나 일반적으로 백틱을 전혀 사용하지 않는 것이 가장 좋습니다. 거의 항상 이것을 사용해야 합니다 $(). 더 강력하며 더 간단한 구문을 사용하여 무한히 중첩될 수 있습니다.

VARIA=$(head -$((${RANDOM} % $(wc -l < file) + 1)) file | tail -1)

답변2

이 명령을 사용하세요.

VARIA=$(head -n "$((${RANDOM} % $(wc -l < test) + 1))" test | tail -n 1)

명령의 결과를 우리가 사용하는 변수에 할당합니다 $(...)(고대 `...`형식은 중첩하기가 더 어렵습니다).

답변3

파일에서 임의의 줄을 읽는 것(그리고 이를 변수에 할당하는 것)의 대안으로 단순화하는 것을 고려하십시오.저수지 샘플링메서드, 변환됨Thrig의 Perl 구현awak와 함께Peter.O의 시딩 개선 사항:

VARIA=$(awk -v seed=$RANDOM 'BEGIN { srand(seed) } { if (rand() * FNR < 1) { line=$0 } } END { print line }' /usr/share/dict/words)

다음은 멋지게 포장된 awk 스크립트입니다.

awk -v seed=$RANDOM '
BEGIN { 
  srand(seed) 
}
{ 
  if (rand() * FNR < 1) { 
    line=$0
  } 
}
END { 
  print line 
}' /usr/share/dict/words

srand()awk의 작동 방식 때문에회의같은 값을 얻다만약에같은 순간에 이 스크립트를 실행합니다.~하지 않는 한다른 무작위 항목으로 시드를 지정합니다. 여기서는 bash의 $RANDOM을 시드로 전달합니다. 여기서는 /usr/share/dict/words의 단어를 텍스트 소스로 선택합니다.

이 방법은 파일에 몇 줄이 있는지 상관하지 않으므로(내 로컬 복사본에는 479,828줄이 있습니다) 매우 유연해야 합니다.

프로그램의 계산을 보기 위해 다양한 줄 번호와 확률을 반복하는 래퍼 스크립트를 작성했습니다.

데모 파일

#!/bin/sh

for lineno in 1 2 3 4 5 20 100
do
  echo "0 .. 0.99999 < ( 1 / FNR == " $(printf 'scale=2\n1 / %d\n' "$lineno" | bc) ")"
  for r in 0 0.01 0.25 0.5 0.99
  do
    result=$(printf '%f * %d\n' "$r" "$lineno" | bc)
    case $result in
      (0*|\.*) echo "Line $lineno: Result of probability $r * line $lineno is $result and is < 1, choosing line" ;;
      (*)      echo "Line $lineno: Result of probability $r * line $lineno is $result and is >= 1, not choosing line" ;;
    esac
  done
  echo
done

결과 :

0 .. 0.99999 < ( 1 / FNR ==  1.00 )
Line 1: Result of probability 0 * line 1 is 0 and is < 1, choosing line
Line 1: Result of probability 0.01 * line 1 is .010000 and is < 1, choosing line
Line 1: Result of probability 0.25 * line 1 is .250000 and is < 1, choosing line
Line 1: Result of probability 0.5 * line 1 is .500000 and is < 1, choosing line
Line 1: Result of probability 0.99 * line 1 is .990000 and is < 1, choosing line

0 .. 0.99999 < ( 1 / FNR ==  .50 )
Line 2: Result of probability 0 * line 2 is 0 and is < 1, choosing line
Line 2: Result of probability 0.01 * line 2 is .020000 and is < 1, choosing line
Line 2: Result of probability 0.25 * line 2 is .500000 and is < 1, choosing line
Line 2: Result of probability 0.5 * line 2 is 1.000000 and is >= 1, not choosing line
Line 2: Result of probability 0.99 * line 2 is 1.980000 and is >= 1, not choosing line

0 .. 0.99999 < ( 1 / FNR ==  .33 )
Line 3: Result of probability 0 * line 3 is 0 and is < 1, choosing line
Line 3: Result of probability 0.01 * line 3 is .030000 and is < 1, choosing line
Line 3: Result of probability 0.25 * line 3 is .750000 and is < 1, choosing line
Line 3: Result of probability 0.5 * line 3 is 1.500000 and is >= 1, not choosing line
Line 3: Result of probability 0.99 * line 3 is 2.970000 and is >= 1, not choosing line

0 .. 0.99999 < ( 1 / FNR ==  .25 )
Line 4: Result of probability 0 * line 4 is 0 and is < 1, choosing line
Line 4: Result of probability 0.01 * line 4 is .040000 and is < 1, choosing line
Line 4: Result of probability 0.25 * line 4 is 1.000000 and is >= 1, not choosing line
Line 4: Result of probability 0.5 * line 4 is 2.000000 and is >= 1, not choosing line
Line 4: Result of probability 0.99 * line 4 is 3.960000 and is >= 1, not choosing line

0 .. 0.99999 < ( 1 / FNR ==  .20 )
Line 5: Result of probability 0 * line 5 is 0 and is < 1, choosing line
Line 5: Result of probability 0.01 * line 5 is .050000 and is < 1, choosing line
Line 5: Result of probability 0.25 * line 5 is 1.250000 and is >= 1, not choosing line
Line 5: Result of probability 0.5 * line 5 is 2.500000 and is >= 1, not choosing line
Line 5: Result of probability 0.99 * line 5 is 4.950000 and is >= 1, not choosing line

0 .. 0.99999 < ( 1 / FNR ==  .05 )
Line 20: Result of probability 0 * line 20 is 0 and is < 1, choosing line
Line 20: Result of probability 0.01 * line 20 is .200000 and is < 1, choosing line
Line 20: Result of probability 0.25 * line 20 is 5.000000 and is >= 1, not choosing line
Line 20: Result of probability 0.5 * line 20 is 10.000000 and is >= 1, not choosing line
Line 20: Result of probability 0.99 * line 20 is 19.800000 and is >= 1, not choosing line

0 .. 0.99999 < ( 1 / FNR ==  .01 )
Line 100: Result of probability 0 * line 100 is 0 and is < 1, choosing line
Line 100: Result of probability 0.01 * line 100 is 1.000000 and is >= 1, not choosing line
Line 100: Result of probability 0.25 * line 100 is 25.000000 and is >= 1, not choosing line
Line 100: Result of probability 0.5 * line 100 is 50.000000 and is >= 1, not choosing line
Line 100: Result of probability 0.99 * line 100 is 99.000000 and is >= 1, not choosing line

원래 공식:

rand() * FNR < 1

수학적으로 다음과 같이 다시 작성할 수 있습니다.

rand() < 1 / FNR

...이것은 행 번호가 증가함에 따라 오른쪽에 감소하는 값을 표시하기 때문에 더 직관적입니다. 방정식 우변의 값이 감소함에 따라 rand() 함수가 우변보다 작은 값을 반환할 확률은 점점 작아집니다.

각 줄 번호에 대해 테스트할 공식의 표현인 범위와 rand()가 출력하는 "1을 줄 번호로 나눈 값"을 인쇄합니다. 그런 다음 일부 샘플 무작위 값을 반복하여 해당 무작위 값이 주어지면 행이 선택되는지 확인합니다.

살펴볼 가치가 있는 몇 가지 예시 사례는 다음과 같습니다.

  • 행 1에서는 rand()가 0 <= rand() < 1 범위의 값을 생성하므로 결과는 항상 (1 / 1 == 1)보다 작으므로 항상 행 1이 선택됩니다.
  • 2행에서는 임의 값이 0.50보다 작아야 한다는 것을 알 수 있습니다. 이는 2행이 선택될 확률이 50%라는 것을 의미합니다.
  • 100번째 줄에서 rand()는 이제 해당 행을 선택하기 위해 0.01보다 작은 값을 생성해야 합니다.

관련 정보