
Это моя программа на языке C, считываемая из stderr, которую я пишу
#include <uninstd.h>
#include <stdio.h>
int main(void) {
char buff[3];
read(2, buff, sizeof(buff));
printf("%s", buff");
return 0;
}
Мой вопрос, как мне отправить stderr в него. Большинство поисковиков показывают, что в bash перенаправление
command 2> file
Но это отправит stderr в файл.
Как мне перейти к моей программе. Как pip,
command 2 "somthing here" ./myprogram
Спасибо за ответы.
решение1
Для многих людей это становится неожиданностью, учитывая, что большинство справочников и документации всегда ссылаются на стандартную ошибку как на выход, но на самом деле это обычно так.уже открыт для чтения+записи. Ваша программа оченьможетпрочитано из файлового дескриптора 2.
(Примечание: в этом ответе я использую фактические номера дескрипторов файлов.С потокитакие, которые stderr
на самом деле не должны соответствовать этим файловым дескрипторам, поскольку программа может изменить их, и это добавляет уровень путаницы в разговор о том, что делают потоки C. Ваша программа использует read()
.)
Файловый дескриптор 2 открыт для чтения и записи.
Для программ в сеансах входа, где не использовалось перенаправление в родительском процессе, файловый дескриптор 2 (стандартная ошибка) обычно является дубликатом файлового дескриптора 0 (стандартный ввод). Они оба ссылаются на один и тот же базовыйописание файла, который обычно является терминалом сеанса входа в систему (открывается и дублируется ttymon
или, в старых системах, getty
в самом начале сеанса).
Если вы читаете из файлового дескриптора 2, вы получаете те же входные данные, что и при чтении из файлового дескриптора 0.
Кстати: Чтение из файлового дескриптора 2 часто выполнялось для таких вещей, как ввод пароля; до того, как /dev/tty
устройство было представлено, примерно в 1977 году. Причиной чтения из файлового дескриптора 2 было получение ввода с исходного терминала, когда файловый дескриптор 0 был перенаправлен в другое место (как, например, в середине конвейера).
Несмотря на то /dev/tty
, что POSIX существует уже давно, более 40 лет, он по-прежнему требует, чтобы файловый дескриптор 2 был открыт для чтения.
Что ваша программа не делает
Чтение из выходного файла дескриптора 2 другой программы — это другое дело. Вы не можете сделать это легкосам по себе, без слияния стандартного вывода со стандартной ошибкой. Обычно это включает в себя серию 3>&1 1>&2 2>&3
или что-то вроде свопов. Некоторые оболочки разрешают каналы на выходном файловом дескрипторе 2, вызывая
prog1 2| prog2
Но такие снаряды редки, и это не то, чтотвойпрограмма нужна в любом случае.
Отправка входных данных в вашу программу
Если вы хотите, чтобы ваша программа, читающая из файлового дескриптора 2, читала из чего-тодругойчем с терминала, вы, конечно, перенаправляете этот файловый дескриптор. Вымогиспользуйте обычныйвходсинтаксис перенаправления ( <
оператор в оболочке), но библиотеки в вашей программе или даже другой код, который вы написали в другом месте, будут предполагать, что они могут выполнять запись в этот файловый дескриптор.
Оболочка позволяет использовать <>
оператор перенаправления, который явно открывает файл как для чтения, так и для записи. Это то, что вы используете при перенаправлении файлового дескриптора 2 вашей программы.
./myprogram 2<>filename
Помимо перенаправления оболочки, есть множество инструментов, которые позволяют манипулировать файловыми дескрипторами. Например: С цепочкой загрузки Лорана Беркоredirfd
инструмент, который поставляется с execline, это перенаправление больше похоже на вашу гипотезу:
redirfd -u 2 filename ./myprogram
Также существует синтаксис оболочки в оболочках Bourne Again и Z (но не в оболочках Almquist) для предоставления «здесь документов» и «здесь строк» файловому дескриптору 2. Обратите внимание, что файловый дескриптор 2 открыттолько для чтенияэтими снарядами в данном случае.
./myprogram 2<<< "here string"
решение2
stderr
предназначен для записи, а не для чтения. Иногда это деликатес dup
( stdin
например, когда все 3 входа/выхода/ошибки подключены к терминалу). Чтобы прочитать stderr другой программы, вы перенаправляете stderr этой программы на stdin другой.
например, to направляет stdout
к файлу, а stderr
to ./myprograms
's stdin
.
command 2>&1 >a_file | ./myprogram
решение3
С помощью таких оболочек, как bash
и zsh
(но не просто POSIX sh
), вы можете перенаправить стандартную ошибку одной программы на стандартный ввод другой программы с помощью firstprogram 2> >(second program)
.
Пример:
$ perl -E 'say "perl stdout"; warn "perl stderr\n"' 2> >(awk '{print "awk", $0}')
perl stdout
awk perl stderr
решение4
Чтобы оболочка настроила перенаправление ввода для stderr
, вы должны использовать <
, <<
или <<<
и префикс в виде номера дескриптора файла:
./myprog 2< somefile.txt
или
./myprog 2<<< "some text"
Хотя если вы перенаправите stderr
таким образом, программа не сможетвыходк нему, что будет означать, что вы не увидите никаких сообщений об ошибках, которые программа (или любые используемые ею библиотеки) может попытаться вывести на печать, и, кроме того, программа будет получать ошибки при попытке записать эти сообщения.
Вы можете пересмотреть, есть ли другой способ сделать то, что вы делаете. По крайней мере, рассмотрите использование, например, fd 3, если идея заключается в том, чтобы предоставить программе какой-то ввод.