В C как напечатать имя файла, который перенаправляется в качестве ввода в оболочке - PullRequest
7 голосов
/ 14 ноября 2009
$cc a.c
$./a.out < inpfilename

Я хочу напечатать inpfilename на стандартный вывод. Как я могу это сделать ? Заранее спасибо за помощь ...

Ответы [ 9 ]

11 голосов
/ 14 ноября 2009

Вы не можете получить имя файла точно в качестве ввода; оболочка будет обрабатывать все эти перенаправления, не сообщая вам.

В случае прямого перенаправления < file вы можете получить путь к файлу, связанный с stdin, используя fstat, чтобы получить для него номер индекса, а затем пройтись по иерархии файлов, аналогично find / -inum, чтобы получить путь, соответствующий Это. (Может быть более одного такого пути к файлу из-за ссылок.)

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

4 голосов
/ 14 ноября 2009

Почему вы хотите это сделать? Вся ваша программа a.out передается из оболочки, является дескриптором открытого файла, stdin.

Пользователь может также сделать это:

cat inpfilename | ./a.out

и теперь у вас нет абсолютно никакого имени для файла (кроме /dev/stdin).

Если a.out необходимо работать с именами файлов, почему бы не принять файл в качестве аргумента командной строки?

2 голосов
/ 14 ноября 2009

Только родительская оболочка будет знать это. Программа a.out всегда будет видеть это как stdin.

1 голос
/ 19 апреля 2018

На самом деле, можно получить имя файла из procfs, так как / proc / * / fd содержит символическую ссылку на открытые файлы:

char filename[bufsize];
int sz = readlink("/proc/self/fd/0", filename, bufsize-1);
filename[sz] = 0;
puts(filename);
1 голос
/ 14 ноября 2009

Ваша операционная система будет снабжать вашу программу входными данными из этого файла. Это прозрачно для вашей программы, и поэтому вы не видите имя файла. Фактически, при некоторых обстоятельствах вам будет выдан ввод, который не поступает из файла, такого как этот:

ls | ./a.out

То, что вы ищете, очень специфично для системы. Возможно, лучшим решением будет передать имя файла в качестве параметра. Таким образом, вы получите имя файла, и вы можете открыть его, чтобы прочитать содержимое.

0 голосов
/ 14 ноября 2009

G'day,

Как указывалось в ответе выше, все, что вы видите, это стандартный дескриптор файла stdin.

Если вы действительно хотите это сделать, вы можете указать, что первой строкой входного файла должно быть имя самого файла.

НТН

0 голосов
/ 14 ноября 2009

fstat(0,sb) (0 - дескриптор стандартного файла) предоставит вам подробную информацию о входном файле, размере, разрешениях (называемых mode ) и иноде устройства, на котором он находится.

В любом случае вы не сможете определить его путь: поскольку иноды Unix не знают, к какому пути они принадлежат, и технически (см. ln) они могут принадлежать более чем одному пути .

0 голосов
/ 14 ноября 2009

Я не думаю, что это возможно, поскольку < просто читает содержимое inpfilename в STDIN.

Если вы хотите, чтобы inpfilename было доступно для вашей программы, но вы также хотите иметь возможность принимать данные из STDIN, настройте вашу программу так, чтобы она принимала аргумент имени файла, и передайте его в FILE. Если аргумент не указан, назначьте STDIN для вашего ФАЙЛА. Тогда ваша процедура чтения ввода использует функции, такие как fscanf, а не scanf, и передаваемый вами ФАЙЛ является либо ссылкой на открытый файл, либо STDIN.

0 голосов
/ 14 ноября 2009

Как вы понимаете, процесс, который запускает a.out, не имеет понятия имени файла, который обеспечивает его стандартный ввод.

Вызов должен быть:

$ ./a.out inputfilename

и парсинг argv в int main( int argc, char* argv[] ) { ... }

или

$ ./a.out <<< "inputfilename"

И получить имя файла от stdin.

Тогда в a.c вам нужно fopen этот файл, чтобы прочитать его содержимое.

...