Não é possível atribuir a saída de comandos aninhados à variável no bash

4

Eu estava tentando atribuir o comando abaixo (que escolhe a linha aleatória do arquivo) a uma variável, mas não funcionando.

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

Abaixo do erro que estou recebendo ao tentar atribuí-lo a uma variável.

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:~$

Eu até tentei o mesmo com loop e não funciona:

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:~$ 
    
por prado 28.11.2016 / 11:27

3 respostas

15

Não está funcionando porque você está tentando aninhar backticks sem escape:

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

Isso realmente tenta executar head -$((${RANDOM} % como um único comando primeiro, e isso dá a você os dois primeiros erros:

$ 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

Em seguida, ele tenta executar

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

O que significa que ele tenta avaliar + 1)) file | tail -1 (que está entre os backticks), e isso fornece os próximos erros:

$ 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'

Você pode contornar isso escapando dos backticks:

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

No entanto, como regra geral, geralmente é melhor não usar backticks. Você deve quase sempre usar $() . É mais robusto e pode ser aninhado indefinidamente com uma sintaxe mais simples:

VARIA=$(head -$((${RANDOM} % $(wc -l < file) + 1)) file | tail -1)
    
por 28.11.2016 / 12:13
2

apenas use este comando

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

para atribuir o resultado de um comando a uma variável, usamos $(...) (a antiga forma '...' é mais difícil de aninhar).

    
por 28.11.2016 / 11:35
2

Como outra opção para ler uma linha aleatória de um arquivo (e atribuí-la a uma variável), considere um método de amostragem de reservatório simplificado, convertido de perl para o awk, com melhoria de semeadura do Peter.O :

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

Aqui está o script awk, bem embrulhado:

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

por causa da maneira como o srand() do awk funciona, você obterá o mesmo valor se executar este script dentro do mesmo segundo, a menos que você o distribua com algo aleatório. Aqui estou selecionando palavras de / usr / share / dict / words, apenas como uma fonte de texto.

Este método não importa quantas linhas estão no arquivo (minha cópia local tem 479.828 linhas), então deve ser bastante flexível.

    
por 28.11.2016 / 17:28