Условно направляя вывод команды в /dev/null в bash
У меня есть следующий скрипт:
flag=false
command_name \
$( flag == false && printf %s '>/dev/null')
Я не ожидаю вывода на терминале, но я все еще получаю некоторые. Если я перенаправить вывод на /dev/null
на той же линии, что и command-name
без этого расширения оно будет подавлено.
Команда является инструментом dx из Android SDK
Редактировать 1: Здесь код из скрипта
dx \
--dex \
$( ( (( flag_v == 1 )) || (( flag_v == 'd' ))) && printf %s '--verbose') \
--no-strict \
--output="../"$app_name.jar \
$(find . -type f -name '*.class') \
$( $dexflag == false && printf %s '>/dev/null')
Как я запускаю инструмент, и он работает, как ожидалось. Я не думаю, что это может быть потоком ошибок.
1 ответ
Условно-перенаправляющий стандартный вывод
Перенаправления являются синтаксисом оболочки - они должны распознаваться на этапе синтаксического анализа, который предшествует расширению параметра, поэтому вы не можете сгенерировать их с помощью расширения переменной (без совершения зла).
То, что вы можете сделать (в bash 4.1 или более поздней версии), иметь безусловное перенаправление, но есть то, что он перенаправляет для изменения:
# Create an out_fd variable that points to stdout (FD 1) if dexflag != "false", or to a new
# handle on /dev/null otherwise
if [[ $dexflag = false ]]; then
exec {out_fd}>/dev/null # maybe put 2>&1 as well to suppress stderr
else
out_fd=1 # use FD 1 (stdout)
fi
# run dex with its stdout redirected to the FD number in "out_fd"
dex ... >&"$out_fd"
# if out_fd is not stdin/stdout/stderr, then go ahead and close it when done.
(( out_fd > 2 )) && exec {out_fd}>&-
Замечания:
- Сравнение строк выполняется в форме
[[ $var = $pattern ]]
(или же[[ $var = "$string" ]]
сделать точное совпадение). Смотрите вики bash-hackers по условному выражению. - В Bash 4.1 или более поздней версии,
exec {fd_varname}>file
открываетfile
и помещает номер дескриптора файла, указывающий на этот файл, в переменнуюfd_varname
,exec {fd_varname}>&-
закрывает файловый дескриптор, номер которого хранится вfd_varname
, - В старых версиях bash вы все еще можете использовать эту логику, но вместо того, чтобы автоматически присваивать номер дескриптора файла, вам придется делать это вручную, вручную назначая неиспользуемый номер FD, который не равен 0, 1 или 2 (которые зарезервированы для stdin, stdout и stderr). Таким образом, в этом случае это может быть
exec 3>/dev/null
или жеexec 3>&1
вif
ветви,>&3
наdex
команда иexec 3>&-
закрыть это.
Безопасное создание списков аргументов условно
Смотрите BashFAQ #50 для длительного обсуждения. Короче говоря: для всего, кроме перенаправления на /dev/null
есть одно простое изменение, необходимое для приведения его в соответствие с лучшими практиками: использование массива.
#!/bin/bash
args=( )
case $flag_v in
1|d) args+=( --verbose ) ;;
esac
while IFS= read -r -d '' filename; do
args+=( "$filename" )
done < <(find . -type f -name '*.class' -print0)
dx --dex --no-strict --output="../$app_name.jar" "${args[@]}"
- Смотрите BashPitfalls #1, объясняющий почему
$(find ...)
(лайк$(ls ...)
) небезопасно, и использование Find входит в лучшие практики. - Смотрите BashFAQ #24, чтобы понять, почему
while read ...; do ...; done < <(find ...)
используется вместоfind ... | while read ...; do ...; done
,