Próbuję napisać skrypt powłoki, który tworzy niektóre katalogi na zdalnym serwerze, a następnie używa scp do kopiowania plików z mojego komputera lokalnego na zdalny. Oto co mam do tej pory:
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
Ilekroć go uruchamiam, otrzymuję ten komunikat:
Pseudo-terminal will not be allocated because stdin is not a terminal.
A skrypt po prostu zawiesza się na zawsze.
Mój klucz publiczny jest zaufany na serwerze i mogę dobrze wykonywać wszystkie polecenia poza skryptem. Jakieś pomysły?
ssh user@server /bin/bash <<EOT…
/bin/bash
wyraźne określenie jest jednym ze sposobów uniknięcia problemu.Odpowiedzi:
Spróbuj
ssh -t -t
(lubssh -tt
w skrócie) wymusić alokację pseudo-tty, nawet jeśli stdin nie jest terminalem.Zobacz także: Kończenie sesji SSH wykonywanej przez skrypt bash
Ze strony ssh:
źródło
ssh -t -t
niessh -tt
? Czy jest jakaś różnica, której nie jestem świadomy?Inappropriate IOCtl for device
-tt
i-t -t
są równoważne; specyfikowanie argumentów osobno lub zgniatanie razem staje się kwestią osobistego stylu / preferencji, a jeśli chodzi o to, istnieją uzasadnione argumenty przemawiające za zrobieniem tego w obie strony. ale tak naprawdę to tylko osobiste preferencje.Również z opcją
-T
z instrukcjaźródło
-tt
Opcja wydaje się najlepsza dla tych z nas, którzy faktycznie chcą TTY i otrzymują komunikat o błędzie OP. Ta-T
odpowiedź jest lepsza, jeśli nie potrzebujesz TTY.Zgodnie z odpowiedzią zanco nie udostępniasz polecenia zdalnego
ssh
, biorąc pod uwagę sposób, w jaki powłoka analizuje wiersz poleceń. Aby rozwiązać ten problem, zmień składnięssh
wywołania polecenia, tak aby zdalne polecenie składało się z poprawnego pod względem składni, ciągu zawierającego wiele wierszy.Istnieje wiele różnych składni, których można użyć. Na przykład, ponieważ polecenia mogą być rurami do
bash
ish
i prawdopodobnie inne powłoki zbyt najprostszym rozwiązaniem jest po prostu połączyćssh
powłoki wywołania z heredocs:Zauważ, że wykonanie powyższego bez
/bin/bash
spowoduje ostrzeżeniePseudo-terminal will not be allocated because stdin is not a terminal
. Zauważ też, żeEOT
jest otoczony pojedynczymi cudzysłowami, dzięki czemubash
rozpoznaje heredoc jako nowdoc , wyłączając lokalną interpolację zmiennych, aby tekst polecenia był przekazywany „tak jak jest”ssh
.Jeśli jesteś fanem rur, możesz przepisać powyższe w następujący sposób:
To samo zastrzeżenie
/bin/bash
dotyczy powyższego.Innym ważnym podejściem jest przekazanie wieloliniowego zdalnego polecenia jako pojedynczego łańcucha, przy użyciu wielu warstw
bash
interpolacji zmiennych w następujący sposób:Powyższe rozwiązanie rozwiązuje ten problem w następujący sposób:
ssh user@server
jest analizowany przez bash i jest interpretowany jakossh
polecenie, a następnie argumentuser@server
przekazywany dossh
polecenia"
rozpoczyna interpolowany ciąg, który po zakończeniu będzie zawierać argument, który zostanie przekazany dossh
polecenia, które w tym przypadku będzie interpretowanessh
jako zdalne polecenie do wykonania jakouser@server
$(
rozpoczyna polecenie do wykonania, a wyjście jest przechwytywane przez otaczający interpolowany ciągcat
to polecenie do wyświetlania zawartości dowolnego pliku, który następuje. Dane wyjściowecat
zostaną przekazane z powrotem do przechwyconego interpolowanego ciągu<<
zaczyna bash heredoc'EOT'
określa, że nazwa heredoc to EOT. Pojedyncze cytaty'
otaczające EOT określają, że heredok powinien być analizowany jako nowdoc , co jest specjalną formą heredoc, w której zawartość nie jest interpolowana przez bash, ale raczej przekazywana w formacie dosłownymKażda treść napotkana między
<<'EOT'
i<newline>EOT<newline>
zostanie dołączona do danych wyjściowych nowdocEOT
kończy nowdoc, co powoduje utworzenie pliku tymczasowego nowdoc i przekazanie go z powrotem docat
komendy wywołującej .cat
wysyła nowdoc i przekazuje dane wyjściowe do przechwyconego interpolowanego ciągu)
kończy polecenie do wykonania"
kończy przechwycony interpolowany ciąg. Zawartość interpolowanego ciągu zostanie przekazana z powrotemssh
jako pojedynczy argument wiersza poleceń, któryssh
będzie interpretowany jako polecenie zdalne do wykonania jakouser@server
Jeśli chcesz uniknąć korzystania z zewnętrznych narzędzi, takich jak
cat
i nie masz nic przeciwko posiadaniu dwóch instrukcji zamiast jednej, użyjread
wbudowanego narzędzia heredoc do wygenerowania polecenia SSH:źródło
cat
rozwiązania polega również na tym, że jest on realizowany w pojedynczej (choć złożonej) instrukcji i nie powoduje, że zmienne tymczasowe zanieczyszczają środowisko powłoki.Dodaję tę odpowiedź, ponieważ rozwiązała ona podobny problem z tym samym komunikatem o błędzie.
Problem : Zainstalowałem cygwin pod Windows i otrzymywałem ten błąd:
Pseudo-terminal will not be allocated because stdin is not a terminal
Rozwiązanie : Okazuje się, że nie zainstalowałem programu i narzędzi klienta openssh. Z tego powodu cygwin używał implementacji ssh systemu Windows, a nie wersji cygwin. Rozwiązaniem było zainstalowanie pakietu openssh cygwin.
źródło
$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
openssh
to może być droga do systemu Windows: superuser.com/a/301026/260710Komunikat ostrzegawczy
Pseudo-terminal will not be allocated because stdin is not a terminal.
wynika z faktu, że nie podano polecenia,ssh
podczas gdy stdin jest przekierowywany z dokumentu tutaj. Z powodu braku określonej komendy jako argumentussh
najpierw oczekuje się interaktywnej sesji logowania (która wymagałaby przydzielenia pty na zdalnym hoście), ale potem musi zdać sobie sprawę, że jej lokalne stdin to nie tty / pty. Przekierowaniessh
standardowego wejścia z dokumentu tutaj zwykle wymaga podania komendy (np./bin/sh
) Jako argumentussh
- w takim przypadku domyślnie żadne pty nie zostaną przydzielone na zdalnym hoście.Ponieważ nie ma żadnych poleceń do wykonania,
ssh
które wymagają obecności tty / pty (takiego jakvim
lubtop
),-t
przełącznik dossh
jest zbyteczny. Wystarczy użyćssh -T user@server <<EOT ...
lub,ssh user@server /bin/bash <<EOT ...
a ostrzeżenie zniknie.Gdyby
<<EOF
nie jest to zmienne specjalne<<\EOT
lub cudzysłowy (tj. Lub<<'EOT'
) wewnątrz dokumentu tutaj, zostanie on rozszerzony przez lokalną powłokę przed jej wykonaniemssh ...
. Skutkuje to tym, że zmienne w tym dokumencie pozostaną puste, ponieważ są zdefiniowane tylko w zdalnej powłoce.Tak więc, jeśli
$REL_DIR
powinien być dostępny zarówno dla powłoki lokalnej, jak i zdefiniowany w powłoce zdalnej,$REL_DIR
musi zostać zdefiniowany poza tym dokumentem przedssh
poleceniem ( wersja 1 poniżej); lub, jeśli<<\EOT
lub<<'EOT'
jest używany, dane wyjściowessh
polecenia można przypisać,REL_DIR
jeśli jedyne wyjście plikussh
komendy na standardowe wyjście jest generowane wecho "$REL_DIR"
obrębie dokumentu ucieczkowego / cytowanego tutaj ( wersja 2 poniżej).Trzecią opcją byłoby zapisanie dokumentu tutaj w zmiennej, a następnie przekazanie tej zmiennej jako argumentu polecenia
ssh -t user@server "$heredoc"
( wersja 3 poniżej).I wreszcie, nie byłoby złym pomysłem sprawdzenie, czy katalogi na hoście zdalnym zostały pomyślnie utworzone (zobacz: sprawdź, czy plik istnieje na hoście zdalnym za pomocą ssh ).
źródło
Wszystkie istotne informacje znajdują się w istniejących odpowiedziach, ale pozwól mi spróbować pragmatycznego podsumowania :
tl; dr:
PRZEKAŻ polecenie, aby uruchomić za pomocą argumentu wiersza polecenia :
ssh jdoe@server '...'
'...'
ciągi mogą obejmować wiele wierszy, dzięki czemu można zachować czytelność kodu nawet bez użycia dokumentu tutaj:ssh jdoe@server ' ... '
NIE przekazuj poleceń przez stdin , jak ma to miejsce w przypadku korzystania z dokumentu tutaj :
ssh jdoe@server <<'EOF' # Do NOT do this ... EOF
Przekazywanie poleceń jako argumentu działa tak, jak jest, i:
exit
instrukcji na końcu swoich poleceń, ponieważ sesja zakończy się automatycznie po przetworzeniu poleceń.W skrócie: przekazywanie poleceń przez stdin jest mechanizmem, który jest niezgodny z
ssh
projektem i powoduje problemy, które należy następnie obejść.Czytaj dalej, jeśli chcesz dowiedzieć się więcej.
Opcjonalne informacje podstawowe:
ssh
Mechanizm akceptowania poleceń do wykonania na serwerze docelowym to argument wiersza poleceń : ostatni operand (argument nie będący opcją) akceptuje ciąg zawierający jedno lub więcej poleceń powłoki.Domyślnie te polecenia są uruchamiane bez nadzoru, w nieinteraktywnej powłoce, bez użycia terminala (pseudo) (
-T
implikowana jest opcja ), a sesja kończy się automatycznie, gdy ostatnie polecenie zakończy przetwarzanie.W przypadku, gdy twoje polecenia wymagają interakcji użytkownika , na przykład odpowiedzi na monit interaktywny, możesz jawnie zażądać utworzenia pty (pseudo-tty) , pseudo terminalu, który umożliwia interakcję z sesją zdalną, za pomocą
-t
opcji; na przykład:ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Zauważ, że interaktywny
read
monit działa poprawnie tylko z pty, więc ta-t
opcja jest potrzebna.Użycie pty ma zauważalny efekt uboczny: stdout i stderr są łączone i oba są zgłaszane przez stdout ; innymi słowy: tracisz rozróżnienie między wyjściem regularnym a wyjściem błędu; na przykład:
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
W przypadku braku tego argumentu
ssh
tworzy interaktywną powłokę - w tym podczas wysyłania poleceń przez stdin , czyli tam zaczyna się problem:W przypadku powłoki interaktywnej
ssh
zwykle domyślnie przydziela pty (pseudo-terminal), chyba że jego standardowe wejście nie jest podłączone do (rzeczywistego) terminalu.Wysyłanie poleceń za pośrednictwem stdin oznacza, że
ssh
„s stdin nie jest podłączony do terminala, więc nie jest tworzony PTY issh
ostrzega Cię odpowiednio :Pseudo-terminal will not be allocated because stdin is not a terminal.
Nawet
-t
opcja, której wyraźnym celem jest zażądanie utworzenia pty, w tym przypadku nie wystarczy : dostaniesz to samo ostrzeżenie.Nieco ciekawie, trzeba następnie dwukrotnie na
-t
opcję do tworzenia siłą PTY:ssh -t -t ...
albossh -tt ...
pokazuje, że naprawdę serio .Być może uzasadnieniem tego bardzo świadomego kroku jest to, że rzeczy mogą nie działać zgodnie z oczekiwaniami . Na przykład w systemie macOS 10.12 pozorny odpowiednik powyższego polecenia, udostępniający polecenia przez stdin i za pomocą
-tt
, nie działa poprawnie; sesja blokuje się po odpowiedzi naread
monit:ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
W mało prawdopodobnym przypadku, gdy polecenia, które chcesz przekazać jako argument, powodują, że wiersz poleceń jest zbyt długi dla twojego systemu (jeśli zbliża się jego długość
getconf ARG_MAX
- patrz ten artykuł ), najpierw skopiuj kod do systemu zdalnego w postaci skryptu ( za pomocą np.scp
), a następnie wysłać polecenie wykonania tego skryptu.W skrócie, użyj
-T
i podaj polecenia za pomocą standardowegoexit
polecenia końcowego , ale pamiętaj, że jeśli potrzebujesz również interaktywnych funkcji, użycie-tt
zamiast tego-T
może nie działać.źródło
Nie wiem, skąd się bierze zawieszenie, ale przekierowanie (lub potokowanie) poleceń do interaktywnego ssh jest ogólnie receptą na problemy. Bardziej niezawodne jest użycie stylu komendy „uruchom jako ostatni argument” i przekaż skrypt w wierszu komend ssh:
(Wszystko w jednym olbrzymie
'
argumencie wieloliniowym wierszu poleceń).Komunikat pseudoterminalny jest spowodowany tym, że
-t
prosi ssh, aby środowisko działające na zdalnym komputerze wyglądało jak rzeczywisty terminal dla programów tam działających. Twój klient ssh nie chce tego zrobić, ponieważ jego własne standardowe wejście nie jest terminalem, więc nie ma możliwości przekazania specjalnych interfejsów API terminala dalej od zdalnego komputera do faktycznego terminala na lokalnym końcu.Co i tak próbujesz osiągnąć
-t
?źródło
-T
zamiast tego użyj opcji .Po przeczytaniu wielu z tych odpowiedzi pomyślałem, że podzielę się uzyskanym rozwiązaniem. Wszystko, co dodałem, to
/bin/bash
przed heredoc i już nie daje to błędu.Użyj tego:
Zamiast tego (daje błąd):
Lub użyj tego:
Zamiast tego (daje błąd):
DODATKOWE :
Jeśli nadal potrzebujesz zdalnego interaktywnego monitu, np. Jeśli skrypt, który uruchamiasz zdalnie, monituje o hasło lub inne informacje, ponieważ poprzednie rozwiązania nie pozwalają na wpisanie monitu.
A jeśli chcesz także zarejestrować całą sesję w pliku
logfile.log
:źródło
Miałem ten sam błąd w systemie Windows przy użyciu emacsa 24.5.1 do łączenia się z niektórymi serwerami firmy za pośrednictwem / ssh: user @ host. Tym, co rozwiązało mój problem, było ustawienie zmiennej „tramp-default-method” na „plink” i za każdym razem, gdy łączę się z serwerem, opuszczam protokół ssh. Aby to działało, musisz mieć zainstalowany plik PuTTY's plink.exe.
Rozwiązanie
źródło
ssh -t foobar @ localhost yourscript.pl
źródło
-t
również, ale w ich konkretnym scenariuszu to nie wystarczy, co skłoniło pytanie do rozpoczęcia.