Я пытаюсь написать сценарий оболочки, который создает некоторые каталоги на удаленном сервере, а затем использует scp для копирования файлов с моего локального компьютера на удаленный. Вот что у меня так далеко:
ssh -t user@server<<EOT
DEP_ROOT='/home/matthewr/releases'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR=$DEP_ROOT"/"$datestamp
if [ ! -d "$DEP_ROOT" ]; then
echo "creating the root directory"
mkdir $DEP_ROOT
fi
mkdir $REL_DIR
exit
EOT
scp ./dir1 user@server:$REL_DIR
scp ./dir2 user@server:$REL_DIR
Всякий раз, когда я запускаю его, я получаю это сообщение:
Pseudo-terminal will not be allocated because stdin is not a terminal.
И сценарий просто висит навсегда.
Мой открытый ключ является доверенным на сервере, и я могу отлично выполнить все команды вне сценария. Любые идеи?
ssh user@server /bin/bash <<EOT…
/bin/bash
явно является одним из способов избежать проблемы.Ответы:
Попробуйте
ssh -t -t
(илиssh -tt
для краткости) принудительно назначить псевдо-tty, даже если stdin не является терминалом.Смотрите также: Завершение сеанса SSH, выполняемого сценарием bash.
Из ssh manpage:
источник
ssh -t -t
и нетssh -tt
? Есть ли разница, о которой я не знаю?Inappropriate IOCtl for device
-tt
и-t -t
эквивалентны; указание аргументов по отдельности или смешение вместе становится вопросом личного стиля / предпочтения, и когда дело доходит до этого, есть веские аргументы для того, чтобы сделать это в любом случае. но на самом деле это просто личные предпочтения.Также с опцией
-T
из руководстваисточник
-tt
опция лучше всего подходит для тех из нас, кто действительно хочет TTY и получает сообщение об ошибке OP. Этот-T
ответ лучше, если вам не нужен TTY.Согласно ответу zanco , вы не предоставляете удаленную команду
ssh
, учитывая, как оболочка анализирует командную строку. Чтобы решить эту проблему, измените синтаксисssh
вызова вашей команды, чтобы удаленная команда состояла из синтаксически правильной многострочной строки.Существует множество синтаксисов, которые можно использовать. Например, поскольку команды могут быть переданы в
bash
иsh
, и, возможно, в другие оболочки, самое простое решение - просто объединитьssh
вызов оболочки с heredocs:Обратите внимание, что выполнение выше без
/bin/bash
приведет к предупреждениюPseudo-terminal will not be allocated because stdin is not a terminal
. Также обратите вниманиеEOT
, что онbash
заключен в одинарные кавычки, поэтому он распознает heredoc как nowdoc , отключая интерполяцию локальной переменной, чтобы текст команды передавался как естьssh
.Если вы являетесь поклонником труб, вы можете переписать вышеизложенное следующим образом:
То же самое
/bin/bash
относится и к вышесказанному.Другой правильный подход - передать многострочную удаленную команду как одну строку, используя несколько уровней
bash
интерполяции переменных следующим образом:Приведенное выше решение устраняет эту проблему следующим образом:
ssh user@server
анализируется bash и интерпретируется какssh
команда, за которой следует аргумент,user@server
передаваемыйssh
команде"
начинает интерполированную строку, которая после завершения будет содержать аргумент, который будет переданssh
команде, которая в этом случае будет интерпретироватьсяssh
как удаленная команда для выполнения какuser@server
$(
начинает команду для выполнения с вывода, захваченного окружающей интерполированной строкойcat
это команда для вывода содержимого любого файла. Выводcat
будет передан обратно в захваченную интерполированную строку<<
начинается Bash Heredoc'EOT'
указывает, что имя heredoc - EOT. Одинарные кавычки,'
окружающие EOT, указывают, что heredoc должен быть проанализирован как nowdoc , который представляет собой особую форму heredoc, в которой содержимое не интерполируется с помощью bash, а передается в буквальном формате.Любой контент, который встречается между
<<'EOT'
и<newline>EOT<newline>
будет добавлен к выводу nowdocEOT
завершает nowdoc, в результате чего создается временный файл nowdoc и передается обратно вызывающейcat
команде.cat
выводит nowdoc и передает вывод обратно в интерполированную строку захвата)
завершает команду для выполнения"
завершает захват интерполированной строки. Содержимое интерполированной строки будет передано обратноssh
как один аргумент командной строки, которыйssh
будет интерпретироваться как удаленная команда для выполнения какuser@server
Если вам нужно избегать использования внешних инструментов, таких как
cat
, и не возражаете против использования двух операторов вместо одного, используйтеread
встроенную функцию с heredoc для генерации команды SSH:источник
cat
решения заключается в том, что оно выполняется в одном (хотя и составном) операторе и не приводит к временным переменным, загрязняющим среду оболочки.Я добавляю этот ответ, потому что он решил проблему, связанную с тем же сообщением об ошибке.
Проблема : я установил Cygwin под Windows и получал эту ошибку:
Pseudo-terminal will not be allocated because stdin is not a terminal
Решение : Оказывается, я не установил клиентскую программу и утилиты openssh. Из-за этого cygwin использовал реализацию ssh для Windows, а не версию cygwin. Решением было установить пакет openssh cygwin.
источник
$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
openssh
этого может быть способ пойти для Windows: superuser.com/a/301026/260710Это предупреждающее сообщение
Pseudo-terminal will not be allocated because stdin is not a terminal.
связано с тем, что команда не указана, вssh
то время как стандартный ввод перенаправлен из документа здесь. Из-за отсутствия указанной команды в качестве аргументаssh
сначала ожидается интерактивный сеанс входа в систему (который потребует выделения pty на удаленном хосте), но затем он должен понимать, что его локальный stdin не является tty / pty. Перенаправлениеssh
stdin из документа здесь обычно требует указания команды (такой как/bin/sh
) в качестве аргумента дляssh
- и в этом случае pty не будет выделяться на удаленном хосте по умолчанию.Поскольку нет никаких команд, которые должны быть выполнены через
ssh
которые требуют наличия tty / pty (например,vim
илиtop
),-t
переключение наssh
излишне. Просто используйтеssh -T user@server <<EOT ...
или,ssh user@server /bin/bash <<EOT ...
и предупреждение исчезнет.Если переменные
<<EOF
не экранированы или не заключены в одинарные кавычки (т. Е.<<\EOT
Или<<'EOT'
) внутри документа here, он будет расширен локальной оболочкой перед выполнениемssh ...
. В результате переменные внутри документа here останутся пустыми, поскольку они определены только в удаленной оболочке.Таким образом, если он
$REL_DIR
должен быть доступен как локальной оболочкой, так и определен в удаленной оболочке,$REL_DIR
он должен быть определен вне документа here передssh
командой ( версия 1 ниже); или, если<<\EOT
или<<'EOT'
используется, выходные данныеssh
команды могут быть назначены,REL_DIR
если единственный выходssh
команды для stdout генерируетсяecho "$REL_DIR"
внутри экранированного / цитируемого здесь документа ( версия 2 ниже).Третий вариант - сохранить документ here в переменной, а затем передать эту переменную в качестве аргумента команды
ssh -t user@server "$heredoc"
( версия 3 ниже).И, наконец, что не менее важно, было бы неплохо проверить, были ли каталоги на удаленном хосте созданы успешно (см .: проверьте, существует ли файл на удаленном хосте с помощью ssh ).
источник
Вся соответствующая информация содержится в существующих ответах, но позвольте мне сделать прагматическое резюме :
ТЛ; др:
Передайте команды для запуска, используя аргумент командной строки :
ssh jdoe@server '...'
'...'
Строки могут занимать несколько строк, поэтому вы можете сохранять код читабельным даже без использования документа здесь:ssh jdoe@server ' ... '
НЕ передавайте команды через стандартный ввод , как в случае использования здесь-документа :
ssh jdoe@server <<'EOF' # Do NOT do this ... EOF
Передача команд в качестве аргумента работает как есть, и:
exit
оператор в конце ваших команд, потому что сеанс автоматически завершится после обработки команд.Вкратце: передача команд через stdin - это механизм, который не согласуется с
ssh
дизайном России и вызывает проблемы, которые затем необходимо обойти.Читайте дальше, если вы хотите узнать больше.
Дополнительная справочная информация:
ssh
Механизм принятия команд для выполнения на целевом сервере является аргументом командной строки : последний операнд (не опциональный аргумент) принимает строку, содержащую одну или несколько команд оболочки.По умолчанию эти команды выполняются без присмотра, в неинтерактивной оболочке, без использования (псевдо) терминала (
-T
подразумевается опция ), и сеанс автоматически заканчивается, когда последняя команда заканчивает обработку.В случае, если ваши команды требуют взаимодействия с пользователем , такого как ответ на интерактивное приглашение, вы можете явно запросить создание pty (pseudo-tty) , псевдотерминала, который позволяет взаимодействовать с удаленным сеансом, используя
-t
опцию; например:ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Обратите внимание, что интерактивная
read
подсказка корректно работает только с pty, поэтому эта-t
опция необходима.Использование pty имеет заметный побочный эффект: stdout и stderr объединяются, и оба сообщения передаются через stdout ; другими словами: вы теряете различие между обычным и ошибочным выводом; например:
ssh jdoe@server 'echo out; echo err >&2' # OK - stdout and stderr separate
ssh -t jdoe@server 'echo out; echo err >&2' # !! stdout + stderr -> stdout
При отсутствии этого аргумента
ssh
создает интерактивную оболочку - в том числе при отправке команд через stdin , где и начинается проблема:Для интерактивной оболочки
ssh
обычно по умолчанию выделяется pty (псевдотерминал), за исключением случаев, когда его стандартный ввод не подключен к (реальному) терминалу.Отправка команд через не означает , что стандартный ввод
ssh
STDIN «S больше не подключен к терминалу, поэтому нет не создается псевдотерминал, иssh
предупреждает вас , соответственно :Pseudo-terminal will not be allocated because stdin is not a terminal.
Даже
-t
вариант, чья экспресс цель состоит в том, чтобы запрос создание Pty, является не достаточно в этом случае вы получите такое же предупреждение.Несколько странно, вы должны затем удвоить к
-t
опции для создания силой: PTYssh -t -t ...
илиssh -tt ...
показывает , что вы на самом деле, на самом деле означает это .Возможно, обоснование необходимости этого очень осознанного шага состоит в том, что все может работать не так, как ожидалось . Например, в macOS 10.12 кажущийся эквивалент вышеупомянутой команды, предоставляющей команды через stdin и использующей
-tt
, не работает должным образом; сеанс застревает после ответа наread
приглашение:ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
В маловероятном случае, когда команды, которые вы хотите передать в качестве аргумента, делают командную строку слишком длинной для вашей системы (если ее длина приближается
getconf ARG_MAX
- см. Эту статью ), сначала подумайте о копировании кода в удаленную систему в форме сценария ( используя, например,scp
), а затем отправьте команду для выполнения этого скрипта.В крайнем случае, используйте
-T
и предоставьте команды через stdin , с конечнойexit
командой, но учтите, что если вам также нужны интерактивные функции, использование-tt
вместо-T
может не работать.источник
Я не знаю, откуда происходит зависание, но перенаправление (или передача) команд в интерактивный ssh - это вообще рецепт проблем. Более надежно использовать стиль «команда-запуск-как-последний-аргумент» и передать сценарий в командной строке ssh:
(Все в одном гигантском
'
многострочном аргументе командной строки).Сообщение псевдотерминала вызвано тем,
-t
что ssh пытается сделать так, чтобы среда, которую он запускает на удаленной машине, выглядела как действительный терминал для программ, которые там работают. Ваш ssh-клиент отказывается делать это, потому что его собственный стандартный ввод не является терминалом, поэтому он не может передавать специальные API-интерфейсы терминала с удаленного компьютера на ваш реальный терминал на локальном конце.Чего ты пытался достичь
-t
?источник
-T
.Прочитав много ответов, я решил поделиться своим решением. Все, что я добавил,
/bin/bash
до heredoc, и это больше не дает ошибки.Использовать это:
Вместо этого (выдает ошибку):
Или используйте это:
Вместо этого (выдает ошибку):
ДОПОЛНИТЕЛЬНО :
Если вам по-прежнему нужна удаленная интерактивная подсказка, например, если скрипт, который вы запускаете удаленно, запрашивает у вас пароль или другую информацию, потому что предыдущие решения не позволяли вам вводить подсказки.
И если вы также хотите записать весь сеанс в файл
logfile.log
:источник
У меня была такая же ошибка в Windows, когда я использовал emacs 24.5.1 для соединения с некоторыми серверами компании через / ssh: user @ host. Что решило мою проблему, так это установив переменную «tramp-default-method» в «plink», и всякий раз, когда я подключаюсь к серверу, я пропускаю протокол ssh. Вы должны иметь установленный в PuTTY файл plink.exe, чтобы это работало.
Решение
источник
ssh -t foobar @ localhost yourscript.pl
источник
-t
тоже использует , но в их конкретном сценарии этого недостаточно, что побудило начать вопрос.