bash: Use uma variável para armazenar o redirecionamento stderr | stdout

16

Existe alguma maneira de redirecionar stdout e stderr via variável, como adicionar opções de comando no script?

Por exemplo, eu tenho um script:

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

Eu posso ver que o OPT é substituído por -p sem problemas e o bash interpreta como opção. Mas o redirecionamento interpreta como nome do diretório.

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory '123/123'
mkdir: created directory '123/123/123'
mkdir: created directory '>/dev'
mkdir: created directory '>/dev/null'
mkdir: created directory '2>&1'

Existe alguma maneira de dizer bash, que $ VAR é redirecionamento, não nomes de dirs.

PS. Pode ser que eu esteja errado, mas quero fazer uma saída detalhada ou não detalhada do meu script. Mas eu preciso de alguma saída, mesmo no modo não-verbose, portanto, não posso apenas redirecionar stdout e stderr inteiros, apenas de alguns comandos dentro do meu script.

    
por rush 10.01.2012 / 10:26

4 respostas

16

Outra solução pode ser a seguinte:

#!/bin/bash

verbose=0

exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
else
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null
fi

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

Em seguida, adicione 1>&3 2>&4 apenas aos comandos dos quais você deseja ver a saída.

    
por 10.01.2012 / 14:18
4

O "como" foi bem explicado em outras respostas; Quero abordar o "porquê" o código do OP não funciona.

A tônica é que os redirecionamentos de saída são marcados antes da expansão da variável. Redirecionamentos são realmente executados após a expansão da variável (daí porque você pode redirecionar a saída para um nome de arquivo que é armazenado em uma variável), mas o shell identifica os redirecionamentos para processamento posterior antes que as variáveis sejam expandidas.

Em outras palavras, quando as variáveis são expandidas, é "muito tarde" para que um caractere de redirecionamento ( < ou > , etc.) seja considerado, porque o shell já identificou quais partes do comando o utilizam vai tratar como redirecionamentos.

Para ler mais, veja os passos 1 e 3 listados abaixo:

LESS='+/^SIMPLE COMMAND EXPANSION' man bash
    
por 11.03.2016 / 22:39
3

Não é interpretado como um "nome de diretório", > está sendo citado, então está sendo tratado literalmente (mais especificamente, você está enviando a string >dev/null 2>&1 . Sua única maneira de contornar isso é usar eval ou gerando um novo shell.

Quanto ao problema "detalhado" mencionado em sua pergunta, faça isso:

verbose=1
if (( verbose )); then
    mkdir -v -p /foo
else
    mkdir -p /foo > /dev/null 2>&1
fi
    
por 10.01.2012 / 10:31
1

Você tem muitos espaços em suas variáveis, que não serão avaliados adequadamente. Você vai querer usar eval para configurar isso.

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

Isso permitirá que $ OPT seja dividido em dois argumentos ( -p e -v ) em vez de um ( -p -v ) e o mesmo com $ TEST. Também mudou para usar /dev/null , pois é muito improvável que você tenha um diretório dev no diretório atual.

    
por 10.01.2012 / 14:35