В коде "{exec> / dev / null; }> / dev / null "что происходит под капотом?

Когда вы перенаправляете список команд, который содержит перенаправление exec, exec> / dev / null, похоже, все еще не применяется после этого, например:

{ exec >/dev/null; } >/dev/null; echo "Hi" 

«Привет» печатается.

Мне показалось, что {} список команд не считается подоболочкой, если он не является частью конвейера, поэтому exec >/dev/null все равно должен применяться в текущей среде оболочки.

Теперь, если вы измените его на:

 { exec >/dev/null; } 2>/dev/null; echo "Hi" 

нет ожидаемого результата; дескриптор 1 файла остается укаченным на / dev / null для будущих команд. Это показано путем повторного использования:

 { exec >/dev/null; } >/dev/null; echo "Hi" 

который не даст выхода.

Я попытался сделать сценарий и пресекать его, но я до сих пор не уверен точно, что здесь происходит.

В каждой точке этого скрипта происходит то, что происходит с дескриптором файла STDOUT?

EDIT: добавление вывода strace:

 read(255, "#!/usr/bin/env bash\n{ exec 1>/de"..., 65) = 65 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 fcntl(1, F_GETFD) = 0 fcntl(1, F_DUPFD, 10) = 10 fcntl(1, F_GETFD) = 0 fcntl(10, F_SETFD, FD_CLOEXEC) = 0 dup2(3, 1) = 1 close(3) = 0 close(10) = 0 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 fcntl(1, F_GETFD) = 0 fcntl(1, F_DUPFD, 10) = 10 fcntl(1, F_GETFD) = 0 fcntl(10, F_SETFD, FD_CLOEXEC) = 0 dup2(3, 1) = 1 close(3) = 0 dup2(10, 1) = 1 fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC) close(10) = 0 fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0 ioctl(1, TCGETS, 0x7ffee027ef90) = -1 ENOTTY (Inappropriate ioctl for device) write(1, "hi\n", 3) = 3 

3 Solutions collect form web for “В коде "{exec> / dev / null; }> / dev / null "что происходит под капотом?”

Давайте следовать

 { exec >/dev/null; } >/dev/null; echo "Hi" 

шаг за шагом.

  1. Есть две команды:

    а. { exec >/dev/null; } >/dev/null { exec >/dev/null; } >/dev/null , за которым следует

    б. echo "Hi"

    Сначала оболочка выполняет команду (a), а затем команду (b).

  2. Выполнение { exec >/dev/null; } >/dev/null { exec >/dev/null; } >/dev/null выполняется следующим образом:

    а. Во-первых, оболочка выполняет перенаправление >/dev/null и запоминает, чтобы отменить его при завершении команды .

    б. Затем оболочка выполняет { exec >/dev/null; } { exec >/dev/null; } .

    с. Наконец, оболочка переключает стандартный вывод обратно туда, где была. (Это тот же механизм, что и в ls -lR /usr/share/fonts >~/FontList.txt – перенаправления выполняются только на время действия команды, к которой они принадлежат.)

  3. После выполнения первой команды оболочка выполняет echo "Hi" . Стандартный выход – там, где он был до первой команды.

Чтобы не использовать суб-оболочку или подпроцесс, когда вывод составного списка {} передан по каналу > , оболочка сохраняет дескриптор STDOUT перед запуском составного списка и восстанавливает его после. Таким образом, exec > в составном списке не выполняет свой эффект за пределами точки, где старый дескриптор восстанавливается как STDOUT.

Давайте посмотрим на соответствующую часть strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n :

  132 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 133 fcntl(1, F_GETFD) = 0 134 fcntl(1, F_DUPFD, 10) = 10 135 fcntl(1, F_GETFD) = 0 136 fcntl(10, F_SETFD, FD_CLOEXEC) = 0 137 dup2(3, 1) = 1 138 close(3) = 0 139 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 140 fcntl(1, F_GETFD) = 0 141 fcntl(1, F_DUPFD, 10) = 11 142 fcntl(1, F_GETFD) = 0 143 fcntl(11, F_SETFD, FD_CLOEXEC) = 0 144 dup2(3, 1) = 1 145 close(3) = 0 146 close(11) = 0 147 dup2(10, 1) = 1 148 fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC) 149 close(10) = 0 

Вы можете видеть, как в строке 134 дескриптор 1 ( STDOUT ) копируется на другой дескриптор с индексом не менее 10 (это то, что делает F_DUPFD , он возвращает наименьший доступный дескриптор, начиная с заданного числа после дублирования на этот дескриптор). Также посмотрите, как в строке 137 результат open("/dev/null") (дескриптор 3 ) копируется на дескриптор 1 ( STDOUT ). Наконец, в строке 147 старый STDOUT сохраненный в дескрипторе 10 , копируется обратно на дескриптор 1 ( STDOUT ). Чистый эффект заключается в том, чтобы изолировать изменение STDOUT на линии 144 (что соответствует внутреннему exec >/dev/null ).

Разница между { exec >/dev/null; } >/dev/null; echo "Hi" { exec >/dev/null; } >/dev/null; echo "Hi" { exec >/dev/null; } >/dev/null; echo "Hi" и { exec >/dev/null; }; echo "Hi" { exec >/dev/null; }; echo "Hi" { exec >/dev/null; }; echo "Hi" заключается в том, что двойное перенаправление делает dup2(10, 1); перед закрытием fd 10, который является копией исходного stdout , перед запуском следующей команды ( echo ).

Это происходит потому, что внешнее перенаправление фактически перекрывает внутреннюю перенаправление. Вот почему он копирует исходный stdout fd после его завершения.

Interesting Posts

Как я могу сделать rsync, который запрашивает подтверждение для каждого отдельного файла?

Поведение подстановки команды bash с помощью команды из строки в переменной

Значение пересечения границ файловой системы, – однофайловая система и т. Д.

Как интерактивно удалить все каталоги, соответствующие заданным критериям?

как дать yes в качестве опции по умолчанию для apt-get install в ubuntu

Как я могу манипулировать содержимым файла, дублируя и меняя некоторые части?

Удаление определенного файла из файла tar

cp vs. mv: какая операция более эффективна?

Несоответствие между двумя расширениями

GRUB: отображает GRUB на внешнем дисплее, подключенном к ноутбуку?

Как добавить Xft suppport в dwm?

Проблемы Grub2 и windows10

Zsh preexec – Как обрезать все ведущие отступы от кодового блока?

Почему «исходная» команда Баша ведет себя по-разному при вызове функции?

Как изменить имя одного раздела sdaX на sdaY?

Linux и Unix - лучшая ОС в мире.