Невозможно назначить вывод вложенных команд переменной в bash

Я решил проблему, понизив llvm-libs и clang до 3.9.0-3 (с 3.9.1-1).

https://bbs.archlinux.org/viewtopic.php?id=221196

4
29.11.2016, 01:53
3 ответа

В качестве другого варианта для чтения случайной строки из файла (и присвоения ее переменной) рассмотрим упрощенный метод отбора проб коллектора , преобразованный из реализации perl thrig в awk, с улучшением раздачи 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

Из-за способа awk srand () работает, вы получите такое же значение , если вы запустите этот скрипт в течение той же секунды , если только вы не засеваете его чем-то другим случайным; здесь я передал $ RANDOM в bash как семя. Здесь я выбираю слова из / usr / share / dict / words, как источник текста.

Этот метод не заботится о том, сколько строк в файле (моя локальная копия содержит 479 828 строк), поэтому он должен быть довольно гибким.

Чтобы увидеть математические вычисления программы в действии, я написал сценарий оболочки, который выполняет итерацию по различным номерам строк и вероятностям:

demo.sh

#!/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, что указывает на 50% вероятность выбора строки 2.
  • в строке 100 rand () теперь необходимо сгенерировать значение меньше 0,01 для того, чтобы линия была выбрана.
2
27.01.2020, 20:45

просто используйте эту команду

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

для присвоения результата команды переменной мы используем $(...) (древнюю форму `...` сложнее вложить).

2
27.01.2020, 20:45

Он не работает, потому что вы пытаетесь вложить незачеркнутые обратные символы:

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

На самом деле он пытается сначала выполнить head -$((${RANDOM} % как одну команду, и это дает вам 2 первые ошибки:

$ 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)
15
27.01.2020, 20:45

Теги

Похожие вопросы