2016-02-11 2 views
3

Примечание редактора: Этот вопрос подвергся нескольким ревизиям, которые изменили характер проблемы, что может привести к недействительности старых комментариев и ответов; его первоначальное название было «Невозможно перенаправить вывод 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). Кроме того, файл пуст. Это не желаемый результат: я хочу, чтобы выход оставался на терминале!

Это из-за порядка, в котором я перенаправляю или это моя переменная, которая не так? EDIT: теперь скрипт работает полностью, заменив "&1" на выходное значение "/dev/tty".

+4

Попробуйте http://shellcheck.net/ перед публикацией здесь. Назначение для закрытия как простой опечатки. – tripleee

+0

Спасибо за ссылку! Однако даже после исправления опечатки возникает проблема: включен ли режим подробностей или нет, выход всегда один и тот же. – Lupuss

+0

@ Lupuss Redirect stderr, а также – 123

ответ

4

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

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

Теперь он отлично работает, когда я нахожусь в режиме «без звука», но не в подробном режиме :) – Lupuss

+0

В свете ретроспективного обзора (к сожалению, ОП менял вопрос несколько раз): Хотя этот ответ показывает общепринятую технику - как отправить stderr для той же цели, что и вывод stdout (перенаправлен) на - , он не адресует окончательную версию проблемы OP, которая проистекает из попытки сохранить перенаправление в файл _descriptor_ в _variable_, который не поддерживается , Quibble: '2> & 1' не перенаправляет stderr _before_ перенаправление stdout; скорее, он перенаправляет stderr на _already-redirected_ stdout, т. е. _after_ stdout был перенаправлен. – mklement0

0

ТЛ; др

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

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

  • Возьмите gniourf_gniourf's совет от комментариев, и использовать вместо 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's совет из комментариев: использовать 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 
Смежные вопросы