Alternar o redirecionamento de Bash com uma variável

4
MUTE='&> /dev/null'
echo "text" $MUTE

Existe uma maneira de fazer isso funcionar mantendo o redirecionamento dentro da variável?

    
por Julen Larrucea 15.03.2016 / 23:56

4 respostas

4

IMHO seria mais elegante usar a presença / valor da variável para fechar condicionalmente os descritores de arquivo, por exemplo,

$ cat myscript.sh
#!/bin/bash

if [ -n "$MUTE" ]; then
    exec &>-
fi

echo somestuff
echo someerr >&2

então

$ ./myscript.sh
somestuff
someerr

mas

$ MUTE=yes ./myscript.sh
$

Se você realmente quiser alternar o redirecionamento, pode considerar a criação de uma função de shell que duplique o (s) descritor (es) de arquivo antes de fechá-los e restaure os duplicados para reativar os fluxos originais eg

#!/bin/bash

function mute {
  case "" in
    "on") 
      exec 3>&1-
      exec 4>&2-
    ;;
    "off") 
      exec 1>&3-
      exec 2>&4-
    ;;
    *)
  esac
}


# Demonstration: 

echo "with mute on: "
mute on
ls somefile
ls nofile

mute off
echo "with mute off: "
ls somefile
ls nofile

Resultado:

$ ./mute.sh
with mute on: 
with mute off: 
somefile
ls: cannot access nofile: No such file or directory
    
por steeldriver 16.03.2016 / 00:55
3

De Manual de Referência do Bash: Simples Expansão do Comando :

  
  1. As palavras que o analisador marcou como atribuições de variáveis (aquelas que precedem o nome do comando) e os redirecionamentos são salvos para processamento posterior.
  2.   
  3. As palavras que não são atribuições de variável ou redirecionamentos são expandidas (consulte Expansões de shell). Se alguma palavra permanecer após a expansão, a primeira palavra será o nome do comando e as restantes serão os argumentos.
  4.   
  5. Os redirecionamentos são executados conforme descrito acima (consulte Redirecionamentos).
  6.   

Isso significa que o analisador de comandos primeiro identifica todos os redirecionamentos, executa as várias expansões e finalmente resolve os redirecionamentos que identificou anteriormente: esses não incluem possíveis redirecionamentos resultantes das expansões.

No entanto, de help eval :

Execute arguments as a shell command.

    Combine ARGs into a single string, use the result as input to the shell,
    and execute the resulting commands.

Portanto, usando eval você pode criar um nível de indireção que permitirá que o comando seja processado duas vezes:

MUTE='&> /dev/null'
eval echo "text" $MUTE
$ MUTE='&> file'
$ eval echo "text" $MUTE
$ cat file
text
    
por kos 16.03.2016 / 00:19
2

Pode-se usar uma função que escreve seu stdin para onde você quiser.

$> MUTE(){  cat /dev/stdin > testFile.txt  ; }                                                    
$> df | MUTE                                                                                      
$> cat testFile.txt
Filesystem     1K-blocks     Used Available Use% Mounted on
udev             1954208        4   1954204   1% /dev
tmpfs             393160     3548    389612   1% /run
/dev/sda1      115247656 95511252  13859056  88% /
none                   4        0         4   0% /sys/fs/cgroup
none                5120        0      5120   0% /run/lock
none             1965792      872   1964920   1% /run/shm
none              102400      128    102272   1% /run/user
cgmfs                100        0       100   0% /run/cgmanager/fs

Ou poderíamos dizer à função para executar o que quisermos com redirecionamento

$> MUTE(){  "$@" > testFile.txt  ; }                                                              
$> MUTE lsblk                                                                                     
$> cat testFile.txt                                                                               
NAME                             MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda                                8:0    0 111.8G  0 disk 
└─sda1                             8:1    0 111.8G  0 part /

Caminho não padronizado, hackery, mas funciona bem :)

    
por Sergiy Kolodyazhnyy 16.03.2016 / 02:16
1

Funciona dessa maneira, não sei se é útil para sua abordagem:

MUTE='&> /dev/null'
bash -c "echo \"text\" $MUTE"
    
por cmks 16.03.2016 / 00:18

Tags