Верно ли заключение, что существует 4 типапоток выводаможем ли мы ссылаться на файл в Linux, если мы не хотим, чтобы он отображался в CLI после выполнения команды?
Возможные ссылки на файл:
- Весь поток вывода
- Только stderr
- Только stdout (включая конечный результат stdout).
- stdout и stderr (исключая конечный результат stdout).
Примечания:
Примером для номера 4 может быть find / -type f -name php.ini 2>/dev/null
. Насколько я понимаю, с помощью этой команды мы не получаем stderr и stdout (кромеОкончательный результат stdoutчто в данном случае является файлом, который мы искали, если он был найден).
решение1
К каждому процессу в системе Unix подключены два выходных потока:стандартный вывод(stdout, файловый дескриптор 1) истандартная ошибка(stderr, file-descriptor 2). Они могут быть перенаправлены независимо друг от друга.Стандартный вводиспользует файловый дескриптор 0.
- Чтобы перенаправить стандартный вывод в файл
file
, используйте>file
или более явный вариант1>file
. Заменитеfile
на ,/dev/null
чтобы отбросить данные. - Чтобы перенаправить стандартную ошибку в файл
file
, используйте2>file
. - Чтобы перенаправить стандартную ошибку туда, куда направляется стандартный вывод, используйте
2>&1
. - Чтобы перенаправить стандартный вывод туда, куда направляются стандартные ошибки, используйте
1>&2
.
Не существует понятия "окончательный результат" потока или процесса. Я полагаю, что все, что отправляется в стандартный вывод, может быть принято как "результат" процесса, если только он также не выводит данные в какой-либо файл, который он открывает сам по себе, или не имеет других побочных эффектов (например, отсоединение файла от каталога, в случае rm
, или обработка ряда сетевых подключений, в случае sshd
). Процесс также возвращает статус выхода (ноль для "успеха" и ненулевой для "неудачи"), который можно рассматривать как "результат" этого процесса, но это не обязательно связано с выходными потоками процесса.
Потоки также могут быть перенаправлены врежим добавления, что означает, что если перенаправление происходит в файл, этот файл изначально не будет обрезан, и любые данные в потоке будут добавлены в конец файла. Это делается с помощью использования >>file
вместо >file
.
В примечании к вопросу команда
find / -type f -name php.ini 2>/dev/null
дано. Это перенаправляет (отбрасывает)толькостандартная ошибка. Стандартный поток вывода вообще не перенаправляется и, следовательно, будет виден целиком в консоли или терминале. Если бы это была промежуточная часть конвейера, стандартный поток вывода был бы подан в стандартный ввод следующей команды в конвейере.
Итак, в заключение я бы сказал, что естьдва(не четыре) выходных потока. Они могут быть перенаправлены независимо друг от друга различными способами, включая отбрасывание их содержимого.
решение2
Каждыйпроцессможет использовать, по соглашению, три стандартных файловых дескриптора. Эти файловые дескрипторы доступны как потоки: stdin
, stdout
, и stderr
.
По умолчанию при запуске процесса из оболочки (CLI) первый подключается к входу вашего терминала (или эмулятора терминала, например xterm), а два других подключаются к выходу вашего терминала.
Вы можете указать оболочке перенаправить их в другое место, например, /dev/null
(где они просто будут поглощены). И вы можете сделать это независимо для stdout
и stderr
. Так что для этого случая действительно есть четыре возможности:
command
command > /dev/null
command 2> /dev/null
command > /dev/null 2> /dev/null
Но ничто не мешает вам перенаправить один или оба в другое место:
command > /tmp/myout 2> /tmp/myerr
В этом случае вы также не получите вывод в своем терминале, но сможете прочитать его позже в файлах /tmp/myout
и /tmp/myerr
.
решение3
Ситуация проще и сложнее, чем можно предположить из вашего вопроса. Перефразируя то, чтоКусаланандаговорит вего ответ, есть два стандартных (обычных) потока ввода-вывода (файловые дескрипторы), которые традиционно настраиваются и используются для вывода: stdout (файловый дескриптор 1) и stderr (файловый дескриптор 2). Наш канонический вопрос, Каковы операторы управления и перенаправления оболочки?, обсуждает, как перенаправить их. Наивно, мы можем перечислить пять различных комбинаций:
╔══════════════════════════════╦═════════════════════════════════════════════╗
║ ║ stderr ║
║ ╟─────────────────────┬───────────────────────╢
║ ║ default │ ║
║ ║ (same as the shell) │ redirected ║
╠════════╤═════════════════════╬═════════════════════╦═══════════════════════╣
║ │ default ║ ║ ║
║ │ (same as the shell) ║ 1 ║ 2 ║
║ ├─────────────────────╠═════════════════════╬═══════════════════════╣
║ stdout │ ║ ║ 4. redirected ║
║ │ ║ ║ to the same file ║
║ │ redirected ║ 3 ╟───────────────────────╢
║ │ ║ ║ 5. redirected ║
║ │ ║ ║ to different files ║
╚════════╧═════════════════════╩═════════════════════╩═══════════════════════╝
но если вы считаете /dev/null
его отличным от файла, а режим добавления — особым случаем, а режим чтения-записи — отличным от режима только записи, а каналы — отличными от файлов, то количество комбинаций увеличивается экспоненциально. Однако, как неоднократно говорилось, «окончательный результат stdout» — это не стандартная фраза Unix/Linux/bash.
Только два?
Другие ответы (возможно, благоразумно) ограничились stdout и stderr (файловые дескрипторы 1 и 2). Я (безрассудно?) считаю, что полный ответ на этот вопрос должен учитывать тот факт, что доступны и другие файловые дескрипторы — до сотен, тысяч или дажеболее миллиона. Например, если вы запустите команду типа diff file1 file2
, diff
программа откроет file1
и file2
, а ядро, вероятно, назначит дескрипторы файлов 3 и 4. Разница в том, что предопределены только дескрипторы файлов 0, 1 и 2. Перенаправление дескрипторов файлов выше 2 обсуждается в следующих местах:
- Справочное руководство Bash: Раздел 3.6 Перенаправления
- Расширенное руководство по написанию сценариев Bash: Глава 20. Перенаправление ввода-вывода
- Разница между 2>&-, 2>/dev/null, |&, &>/dev/null и >/dev/null 2>&1(вопрос U&L)
- Можно ли использовать больше файловых дескрипторов, помимо обычных stdin/stdout/stderr (0, 1, 2)?(вопрос Stack Overflow)
Например, посмотрите на этот пример высокого дескриптора файла:
$ cat canine.c #include <stdio.h> #include <string.h> основной() { int i, len; char msg[] = "Привет, собака.\n"; len = strlen(сообщение); я = запись(17, сообщ, длина); если (я == длина) printf("Успех! i = %d = len\n", i); иначе если (i == -1) { printf("Ошибка! i = %d (len = %d)\n", i, len); ошибка(""); } еще printf("Неожиданный результат: i = %d, len = %d\n", i, len); } $ сделать собаку cc собачий.c -o собачий $ ./собачий Ошибка! i = -1 (len = 12) Неверный дескриптор файла $ ./собачий 17> животное Успех! i = 12 = len $ ls -l всего 70 -рв-р--р-- 1мое имя пользователя мое имя группы 12 апр 12 13:36 животное -rwxr-xr-x 1мое имя пользователя мое имя группы67067 12 апр 13:36 собака -рв-р--р-- 1мое имя пользователя мое имя группы 358 12 апр 13:36 canine.c $ кошка животное Привет, собака.
Предупреждение: я не уверен, что вышеизложенное будет работать для всех версий всех оболочек.
Стандартные программы не записывают в файловые дескрипторы выше 2 (если только они не получили этот файловый дескриптор из ядра, открыв файл, установив сетевое соединение или что-то в этом роде). Но если у вас есть (нестандартная) программа, которая это делает, вы можете перенаправить эти файловые дескрипторы.
А если у вас всего 100 файловых дескрипторов и вы учитываете только то, перенаправлен ли каждый из них или нет, то у вас есть более миллиона (1 000 000 000 000 000 000 000 000 000 000) возможных комбинаций.