Можно ли писать в другие файловые дескрипторы в C?

Aquí hay una solución alternativa:

sed -re ':b; s,[^\x08]\x08,,g; tb'

  • :b:Etiquetab
  • s,[^\x08]\x08,,g:Empareje un carácter de retroceso que no sea -con un carácter de retroceso y elimine ambos
  • tb:Si la directiva anterior shizo algo, regrese a la etiquetab
1
11.08.2017, 23:09
4 ответа

Можно ли писать в другие файловые дескрипторы в C?

Да.

Большинство процессов наследуют 3 дескриптора открытых файлов от родителя, который их запустил.

stdin, stdoutи stderr. Это файловые дескрипторы 0-2 соответственно.

Я полагаю, что fd 0 ( stdin) открыт в режиме только для чтения, поэтому ваша программа на языке C может читать этот файловый дескриптор, но не может записывать в него.

Когда ваша программа открывает другой файл, она получает следующий файловый дескриптор в возрастающем порядке.

0
27.01.2020, 23:11

Я не совсем знаком с C, поэтому могут быть лучшие способы сделать это, но вы можете просто использовать системный вызов ( man 2 write):

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

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

Если вы пишете в конвейер или сокет, а другая сторона не читает данные, то записывающее приложение (то есть вызов write()) заблокируется, когда буферы будут заполнены.

Вы можете увидеть файловые дескрипторы в /proc/$PID/fd

3
27.01.2020, 23:11

Предполагая, что дескриптор открыт, C действительно можетwrite(или, что более вероятно, использовать вызов более высокого -уровня, который в конечном итоге сведется кwrite(2))этому дескриптору. Вот этоwrite2three.c

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    if ((fd = dup(3)) == -1) err(1, "dup failed");
    dprintf(fd, "hello\n");
    exit(EXIT_SUCCESS);
}

.

$ make write2three  
cc     write2three.c   -o write2three
$./write2three
write2three: dup failed: Bad file descriptor
$ rm out
$./write2three 3>out
$ cat out
hello
$ 

После этого вам может понадобиться очистить оболочку.

$ exec 3>&-
$ 
2
27.01.2020, 23:11

Чтобы уточнить еще несколько вещей. В:

echo foo >&3

echoне записывает "foo\n"в свой файловый дескриптор 3. echoвсегда пишет в стандартный вывод, в свой файловый дескриптор 1. Он вызывает системный вызов write()с целым числом 1в качестве первого аргумента, указатель на область в памяти, которая начинается с foo\nв качестве второго аргумента и4(длиныfoo\n)в качестве третьего.

В C вы бы написали это write(1, "foo\n", 4). В приведенном выше коде оболочка перенаправляет fd 1 на то же описание открытого файла , что и в fd 3, перед вызовомecho(с помощью системного вызова dup2()). Таким образом, хотя это функционально эквивалентно, это не то же самое, что выполнение write(3, "foo\n", 4). По сути, это что-то вроде (упрощенного):

if (pid = fork())
  waitpid(pid,...);
else {
  dup2(3, 1);
  execlp("echo", "foo", 0);
} 

И echoделаетwrite(1, "foo\n", 4)

За исключением того, что практически во всех оболочках echoвстроен, поэтому нет forkили exec. Вместо этого оболочка делает:

saved_stdout = dup(1);
dup2(3, 1);
builtin_echo("foo");
dup2(saved_stdout, 1); close(saved_stdout); /* restore stdout */

(где builtin_echo()— функция, выполняющая write(1, "foo\n", 4)в том же процессе ).

Для команды, которая выполняет write(3, "foo\n", 4), вы можете взглянуть на ksh/ zshвстроенную команду print -u3 foo.

Теперь каждый процесс может использовать файловые дескрипторы по своему усмотрению. За исключением того, что 0, 1 и 2 по соглашению зарезервированы для stdin, stdout и stderr. Другие fds, как правило, не являются специальными, но в оболочках (, которые являются всего лишь одним типом приложений ), fds от 0 до <some-value>, где некоторое значение равно как минимум 9, зарезервированы для использования пользователем (оболочки. ). Скорлупа не будет смешиваться с ними для собственного внутреннего супа. Например, мой saved_stdout = dup(1)выше был приблизительным. В результате,оболочка позаботится о том, чтобы saved_stdoutбыло значение больше, чем <some-value>.

Теперь, поскольку к fds за пределами 0,1,2 не прилагается соглашение, вы не можете ожидать, что что-либо будет открыто на fd 3. Скорее всего, оно будет закрыто. Или, если это не так, вероятно, вызывающая сторона вашего скрипта просто забыла закрыть его (или добавить к нему флаг O_CLOEXC), так как не было причин, по которым он оставил его открытым для вас, как никто не ожидает. все, что должно быть открыто на fd 3.

Вы бы использовали fd 3, если бы знали, что он был открыт на что-то, как правило, вами заранее в том же скрипте, как в:

 {
   var=$(cmd 2>&1 >&3)
 } 3>&1

Там, где fd 3 было определено как dup()fd 1 до , мы используем его для cmddup()обратно на fd 1.

7
27.01.2020, 23:11

Теги

Похожие вопросы