使用变量切换 Bash 重定向

使用变量切换 Bash 重定向
MUTE='&> /dev/null'
echo "text" $MUTE

有没有办法让重定向保持在变量内部?

答案1

在我看来,使用变量的存在/值来有条件地关闭文件描述符会更优雅,例如

$ cat myscript.sh
#!/bin/bash

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

echo somestuff
echo someerr >&2

然后

$ ./myscript.sh
somestuff
someerr

$ MUTE=yes ./myscript.sh
$

如果你真的想切换重定向,您可以考虑创建一个 shell 函数,在关闭文件描述符之前复制它们,然后恢复重复项以重新启用原始流,例如

#!/bin/bash

function mute {
  case "$1" 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

结果:

$ ./mute.sh
with mute on: 
with mute off: 
somefile
ls: cannot access nofile: No such file or directory

答案2

Bash 参考手册:简单命令扩展

  1. 解析器标记为变量赋值(命令名前面的词)和重定向的词被保存以供稍后处理。
  2. 那些不是变量赋值或重定向的词会被扩展(参见 Shell 扩展)。如果扩展后还有剩余的词,则第一个词将被视为命令的名称,其余的词将被视为参数。
  3. 重定向按上述方式执行(参见重定向)。

这意味着命令解析器首先识别所有重定向,然后执行各种扩展,最后解析它先前识别的重定向:这些不包括扩展可能导致的重定向。

但是来自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.

因此,eval你可以创建一种间接级别,允许命令被处理两次:

MUTE='&> /dev/null'
eval echo "text" $MUTE
$ MUTE='&> file'
$ eval echo "text" $MUTE
$ cat file
text

答案3

您可以使用一个函数将其写入stdin您想要的任何位置。

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

或者我们可以告诉函数通过重定向执行我们想要的任何操作

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

非标准方式,黑客手段,但它确实有效:)

答案4

它是这样工作的,我不知道它是否适用于你的方法:

MUTE='&> /dev/null'
bash -c "echo \"text\" $MUTE"

相关内容