Невозможно перенаправить на дескриптор файла, хранящийся в переменной

Примечание редактора: этот вопрос подвергся нескольким изменениям, которые изменили природу проблемы, что может сделать недействительными старые комментарии и ответы; его первоначальное название было "Невозможно перенаправить вывод Bash в /dev/null".

Я пытаюсь создать небольшой скрипт Bash, для которого я хотел бы реализовать тихий режим. По сути, я просто хотел бы скрыть большую часть вывода по умолчанию и, в случае, если я запускаю его с -v покажи весь вывод.

Итак, в начале моего сценария я поставил:

#!/bin/bash
declare output=''
if [ "$1" = -v ]; then
  output="&1"
else
  output="/dev/null"
fi

Тогда в моих сценариях у меня есть:

{
  # whatever commands...
} > $output 2>&1

Тихий режим работает хорошо. Однако, если я попробую подробный режим, файл с именем & или же &1 (основываясь на моем output переменная) создается. Также файл пуст. Это не желаемый результат: я хочу, чтобы вывод оставался на терминале!

Это из-за того, в каком порядке я перенаправляю или моя переменная неверна? РЕДАКТИРОВАТЬ: сценарий теперь работает полностью, заменив "&1" в качестве выходного значения с "/dev/tty",

2 ответа

Решение

Скорее всего, выводится сообщение об ошибке. Обратите внимание, что с > /dev/null только стандартный вывод перенаправлен, а стандартный - нет. Ты можешь использовать 2>&1 перенаправить stderr на стандартный вывод перед перенаправлением стандартного вывода. Что-то вроде:

{
  # whatever commands...
} > $output 2>&1

ТЛ; др

  • Вы не можете хранить перенаправления в файловые дескрипторы (&1 в вашем случае) в переменных - если вы это сделаете, вместо этого вы создадите файл с этим именем (файл с буквальным именем &1 в твоем случае).

  • настройка $output в /dev/tty не рекомендуется, потому что вы всегда выводите на терминал, что предотвращает захват подробного вывода в файл; например, script -v > file не сработает

  • Воспользуйтесь gniourf_gniourf из комментариев и используйте exec вместо: exec > /dev/null 2>&1 или, используя специфичный для Bash синтаксис, exec &>/dev/null заставляет замолчать оставшуюся часть сценария.


Перенаправление на файловый дескриптор работает только:

  • если цель перенаправления является литералом, а не ссылкой на переменную.
  • если между >и цель.
date > &1 # !! SYNTAX ERROR: syntax error near unexpected token `&'

date >&1  # OK - but works with a *literal* `&1` only

Если вы используетепеременную, это не имеет значения, потому что содержимое переменной неизменно интерпретируется как имя файла- поэтому вы не получили синтаксическую ошибку, а получили выходной файл с буквальным именем &1вместо.

output='&1'
date >$output  #  !! Creates a *file* named '&1'.
date > $output #  !! Ditto.

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

#!/usr/bin/env bash

if [[ $1 == '-v' ]]; then
  : # verbose mode: redirect nothing
else 
  # quiet mode: silence both stdout and stderr
  exec &>/dev/null
fi

echo 'hello'      # will only print with -v specified
echo 'hello' >&2  # ditto
Другие вопросы по тегам