Использование тире (-) вместо имени файла

110

Для команды, если использовать -в качестве аргумента вместо имени файла, будет означать STDIN или STDOUT.

  1. Но в этом примере он создает файл с именем -:

    echo hello > -

    Как я могу сделать -в этом примере означает STDOUT?

  2. И наоборот, как я могу -обозначить файл, указанный -в примерах, таких как:

    cat -
Тим
источник
3
Поскольку мне, очевидно, нужно иметь 50 репутации, чтобы комментировать напрямую ... В комментарии / dev / stdin / dev / stdout AIX, который является законным производным UNIX, не имеет этих псевдоустройств. И, как еще один комментарий, LINUX ни в коем случае не является производной от UNIX. Это POSIX-совместимый рабочий код, и на данный момент это самая популярная из операционных систем UNIX, но, не сомневайтесь, это не UNIX. Но суть ответов здесь верна. Обозначение «-» не интерпретируется оболочкой как особенное и, таким образом, передается непосредственно каждому отдельному приложению как ARG. Если приложение не распознается
Есть также 2>&-конструкция, что означает «закрыть дескриптор 2».
user3132194
@ user95873, я полагаю, вы хотели сказать следующее: хотя Linux является Unix-подобным, не каждый Unix-подобный (или настоящий UNIX) является Linux . Вопрос о том, является ли Linux верным или нет, UNIX (т.е. соответствует спецификации Single UNIX) не имеет отношения к проблеме / dev / std {in, out, err}. Так как / dev / std {in, out, err} - это добавленная функция, не пропущенная .
саша

Ответы:

156

Использование -в качестве имени файла значения stdin / stdout - это соглашение, которое используют многие программы. Это не специальное свойство имени файла. Ядро не распознает -как особые, поэтому любые системные вызовы со ссылкой на -имя файла будут использовать -буквально как имя файла.

С перенаправлением bash -не распознается как специальное имя файла, поэтому bash будет использовать его как буквальное имя файла.

Когда catвидит строку -как имя файла, он воспринимает ее как синоним stdin. Чтобы обойти это, вам нужно изменить строку, которая catвидит таким образом, что она по-прежнему ссылается на файл с именем -. Обычный способ сделать это состоит в том, чтобы префикс имени файла с путем - ./-, или /home/Tim/-. Этот метод также используется для обхода подобных проблем, когда параметры командной строки конфликтуют с именами файлов, поэтому файл, на который ссылаются ./-e, не отображается, например, как параметр -eкомандной строки для программы.

CAMH
источник
37
Стоит добавить , что /dev/stdinи /dev/stdoutповсеместно доступны и могут быть использованы вместо -конвенции.
JMDD
Кроме того, в catслучае, используя перенаправление вместо перечисления аргумент может помочь: cat <-; однако было бы трудно смешивать и сопоставлять это с конкатенацией более одного файла за раз.
JMDD
10
@jmtd: / dev / std {in, out} не доступны для всех. Не у всех юниксов есть это.
Camh
2
Интересно, я предположил, что они были частью POSIX (но не могу подтвердить). Они присутствуют, по крайней мере, в Linux, BSD и Solaris. Можете ли вы привести пример современной UNIX, в которой их нет?
JMTD
1
@camh Не уверен, что вы получили уведомление, и это очень, очень старая тема; Я не уверен, если вы можете, но мне очень любопытно, если вы знаете ответ на jmtdвопрос? :)
Поворот
18
  1. Вместо echo hello > -, вы можете использовать echo hello > /dev/stdout.

    Хотя '-' - это соглашение, которое должно быть реализовано каждой программой, желающей его поддерживать /dev/stdin, /dev/stdoutи /dev/stderr, когда поддерживается ОС (по крайней мере, Solaris, Linux и BSD), не зависит от приложения и будет работать как вы. намерены.

jlliagre
источник
9

Как уже упоминалось в camh , -это просто соглашение об именах, используемое некоторыми программами. Если вы хотите сослаться на эти потоки с помощью файлового дескриптора, который распознает оболочка, jiliagre был прав, когда вы использовали имя /dev/stdinили /dev/stdoutвместо него. Эти имена файлов должны работать в любом месте, где будет работать нормальное имя файла.

  1. Тем не менее, ваш первый пример немного глупый. Любой вывод, который будет перехвачен оператором перенаправления для записи в файл, уже включен в стандартный вывод, поэтому перенаправление и обратная запись туда, откуда он пришел, бесполезно. Поведение, которое вы используете, это канал, а не редирект:

    echo hello |
  2. Во втором примере вам просто нужно указать, что вам нужен литеральный файл с таким именем, а не его внутренний псевдоним. Вы можете сделать это проще всего, указав путь к файлу следующим образом:

    cat ./-
Калеб
источник
6

Что касается 1, программа должна поддерживать его. Вы не можете просто использовать это произвольно. Что касается 2, перенаправить ввод с (например, cat < -).

bahamat
источник
1

Подход «-» имеет много проблем. Прежде всего, это требует интерпретации символа «-», и многие программы не выполняют такую ​​интерпретацию. Более того, есть некоторые программы, которые интерпретируют дефис как разделитель, обозначающий конец параметров командной строки. Программы написаны для работы с аргументами имени файла, подход «-» - хак, хороший, но слабый.

Лучший способ это:

$ echo hello > /dev/fd/1

/dev/stdout является символической ссылкой /dev/fd/1

b3h3m0th
источник
Перенаправление интерпретируется оболочкой, а не вызываемой программой.
sherrellbc