Что делает `<& -`?


20

Я скопировал фрагмент Bash в фоновую команду ssh, выполненную удаленно:

ssh user@remote <<CMD
some process <&- >log 2>error &
CMD

Что делает <&-?
Я думаю, что это так же, как< /dev/null

Мое следующее понимание , что три основные файловые дескрипторы ( stdin, stdout, stderr) должны быть закрыты , чтобы предотвратить:

  1. Работа на заднем плане и сценарий выхода - как-то конфликтует?
  2. Когда терминал закрывается, все процессы, которые принимают стандартный ввод от терминала, закрываются?

Обязательная перекрестная ссылка: см. Что такое операторы управления и перенаправления оболочки? - хотя все, что говорится об этом операторе, это то, что он «может использоваться для закрытия или дублирования файловых дескрипторов», и вы должны «увидеть соответствующий раздел руководства по вашей оболочке».
G-Man говорит «Восстановить Монику»

Если я правильно помню, ssh -nNT user@remote 'command'создаст неинтерактивный сеанс SSH. Добавьте &к фону это, добавьте nohupк, commandчтобы держать это работающим, если Ваше соединение умирает.
Марк К Коуэн

1
@MarkKCowan man sshпредполагает, что -N полностью отключает запуск удаленной команды, и быстрый тест поддерживает это.
Том Хант

Ах да, я использовал -nNTR для обратной переадресации портов. Проигнорируйте -N и -R тогда :)
Марк К Коуэн

Ответы:


30

<&-это не совсем то же самое, что < /dev/null. <&-закрывает fd 0, тогда как < /dev/nullперенаправляет его с устройства /dev/null, которое никогда не предоставляет никаких данных и всегда дает EOF при чтении. Разница в основном заключается в том, что при read(2)вызове из закрытого FD ( <&-случай) произойдет ошибка с EBADF, тогда как при вызове из FD с нулевым перенаправлением не будет прочитано ни одного байта (условие конца файла). Если ваша программа никогда не читает со стандартного ввода, различие не имеет значения.

Закрытие FD - хорошая практика, если вы что-то делаете в фоновом режиме, поскольку фоновый процесс зависнет, если он попытается что-то прочитать из TTY. Этот пример не полностью обрабатывает все, что должен; в идеале должен быть вызов nohupили setsidвызов где-то, чтобы полностью отделить фоновый процесс.


Так что я должен использовать nohupв дополнение к закрытию файловых дескрипторов?
Эрик Фрэнсис

2
Самый тщательный метод (который имитирует способ, которым программы демонизируют себя) - это что-то вроде setsid some process <&- >path/to/log 2>path/to/error. Более быстрый метод что-то вроде nohup some process &.
Том Хант

2
@EricFrancis: Использование nohupздесь не имеет смысла. nohupпредотвратить процесс от получения HUPсигнала, когда его терминал управления закрыт. Но у вас не было терминала в этом случае.
Cuonglm

@TomHunt: фоновый процесс не зависал, сессия ssh делала.
Cuonglm

2
не стоит закрывать fds 0, 1 и 2 ... вы не хотите, чтобы следующий созданный fd принимал одно из этих значений. лучше перенаправить их в / dev / null
Мюррей Дженсен

7

Смотрите man bash:

  [n]<&word

используется для дублирования дескрипторов входных файлов. Если он wordрасширяется до одной или нескольких цифр, дескриптор файла, обозначенный nкак, создается как копия этого дескриптора файла. Если цифры word не указывают дескриптор файла, открытый для ввода, возникает ошибка перенаправления. Если слово равно, -дескриптор файла nзакрывается. Если nне указан, используется стандартный ввод (дескриптор файла 0).


Правильное определение заключается в том, что неизвестно, что происходит, когда у вас есть [n]<&wordи слово содержит более одной цифры.
Щил

Что вы имеете в виду? Это man bashневерно?
Эрик Фрэнсис

@EricFrancis, потому что он не указан в стандарте, bashрешает реализовать его разумным способом (для некоторого подходящего определения «нормального»). Другие оболочки могут или не могут сделать это.
Муру

@muru Вопрос помечен bash, а не posix-shell.
Бармар

@ Бармар хорошо. Так...?
Муру

7

<&- закрыть стандартный ввод.

Общий вид, определяемый POSIX , является:

[n]<&word

Его назначение сделать дескриптор файла n- это копия дескриптора файла, обозначенная как word. Standard in предполагается, если nопущен, а если wordесть -, дескриптор файла nбудет закрыт.

Это не то же самое, что </dev/null, когда, в случае </dev/null, стандартный ввод все еще открыт, и был перенаправлен в другое место.

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

Вы можете запустить команду на удаленной машине, не подключая ее к сеансу ssh, используя screen или tmux :

ssh user@remote 'screen -S test -d -m command'

Почему голосование за?
Cuonglm
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.