Pseudo-terminal nie zostanie przydzielony, ponieważ stdin nie jest terminalem

345

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?

Mateusz
źródło
4
Możesz po prostu określić terminal, który ma być używanyssh user@server /bin/bash <<EOT…
Buzut 11.04.16
3
@Buzut: Prawdopodobnie masz na myśli powłokę , ale tak, /bin/bashwyraźne określenie jest jednym ze sposobów uniknięcia problemu.
mklement0
1
@ mklement0 rzeczywiście, o to mi chodziło. Dziękujemy za poprawienie tego;)
Buzut

Odpowiedzi:

512

Spróbuj ssh -t -t(lub ssh -ttw 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:

-T      Disable pseudo-tty allocation.

-t      Force pseudo-tty allocation.  This can be used to execute arbitrary 
        screen-based programs on a remote machine, which can be very useful,
        e.g. when implementing menu services.  Multiple -t options force tty
        allocation, even if ssh has no local tty.
Carok
źródło
21
Mam podobny problem w uruchamianym tutaj skrypcie. Dodałem -t -t, ale teraz pojawia się nowy błąd. „tcgetattr: Niewłaściwy ioctl dla urządzenia”
MasterZ
5
Dlaczego ssh -t -tnie ssh -tt? Czy jest jakaś różnica, której nie jestem świadomy?
Jack
3
@MasterZ To samo tutaj. Byłoby miło uzyskać odpowiedź na to pytanieInappropriate IOCtl for device
krb686,
11
@Jack -tti -t -tsą 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.
JDS
5
Co to znaczy, gdy mówi „nawet jeśli ssh nie ma lokalnego tty”?
CMCDragonkai
192

Również z opcją -Tz instrukcja

Wyłącz alokację pseudo-tty

Emil Bojda
źródło
11
Ta odpowiedź wymaga więcej punktów - jest to prawidłowa odpowiedź i nie jest zbyt długa jak odpowiedź zanco, jej absurd, że „och, mimo to przydziel TTY za pomocą -t -t” dostaje 107 punktów, kiedy możesz po prostu całkowicie pominąć
nhed
2
Po prostu głosowałem; zadziałało to dla mnie lepiej niż -t -t
Vincent Hiribarren
15
„-t -t” działa, jednak z „-T” dostaję „sudo: przepraszam, musisz mieć tty, aby uruchomić sudo”
Ivan Balashov
3
@nhed: -ttOpcja wydaje się najlepsza dla tych z nas, którzy faktycznie chcą TTY i otrzymują komunikat o błędzie OP. Ta -Todpowiedź jest lepsza, jeśli nie potrzebujesz TTY.
ErichBSchulz
3
@nhed - jasne - ale jestem pewien, że inni, tacy jak ja, przybyli tutaj z Googlinga w komunikacie o błędzie. Nie wydaje się nierozsądne wyjaśnienie, w jaki sposób inni pracownicy Google powinni wybierać między 2 konkurencyjnymi odpowiedziami. albo może nie. nie wiem
ErichBSchulz
91

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ę sshwywoł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 bashi shi prawdopodobnie inne powłoki zbyt najprostszym rozwiązaniem jest po prostu połączyć sshpowłoki wywołania z heredocs:

ssh user@server /bin/bash <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

Zauważ, że wykonanie powyższego bez /bin/bash spowoduje ostrzeżenie Pseudo-terminal will not be allocated because stdin is not a terminal. Zauważ też, że EOTjest otoczony pojedynczymi cudzysłowami, dzięki czemu bashrozpoznaje 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:

cat <<'EOT' | ssh user@server /bin/bash
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

To samo zastrzeżenie /bin/bashdotyczy powyższego.

Innym ważnym podejściem jest przekazanie wieloliniowego zdalnego polecenia jako pojedynczego łańcucha, przy użyciu wielu warstw bashinterpolacji zmiennych w następujący sposób:

ssh user@server "$( cat <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
)"

Powyższe rozwiązanie rozwiązuje ten problem w następujący sposób:

  1. ssh user@serverjest analizowany przez bash i jest interpretowany jako sshpolecenie, a następnie argument user@serverprzekazywany do sshpolecenia

  2. "rozpoczyna interpolowany ciąg, który po zakończeniu będzie zawierać argument, który zostanie przekazany do sshpolecenia, które w tym przypadku będzie interpretowane sshjako zdalne polecenie do wykonania jakouser@server

  3. $( rozpoczyna polecenie do wykonania, a wyjście jest przechwytywane przez otaczający interpolowany ciąg

  4. catto polecenie do wyświetlania zawartości dowolnego pliku, który następuje. Dane wyjściowe catzostaną przekazane z powrotem do przechwyconego interpolowanego ciągu

  5. <<zaczyna bash heredoc

  6. '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łownym

  7. Każda treść napotkana między <<'EOT'i <newline>EOT<newline>zostanie dołączona do danych wyjściowych nowdoc

  8. EOTkończy nowdoc, co powoduje utworzenie pliku tymczasowego nowdoc i przekazanie go z powrotem do catkomendy wywołującej . catwysyła nowdoc i przekazuje dane wyjściowe do przechwyconego interpolowanego ciągu

  9. ) kończy polecenie do wykonania

  10. "kończy przechwycony interpolowany ciąg. Zawartość interpolowanego ciągu zostanie przekazana z powrotem sshjako pojedynczy argument wiersza poleceń, który sshbędzie interpretowany jako polecenie zdalne do wykonania jakouser@server

Jeśli chcesz uniknąć korzystania z zewnętrznych narzędzi, takich jak cati nie masz nic przeciwko posiadaniu dwóch instrukcji zamiast jednej, użyj readwbudowanego narzędzia heredoc do wygenerowania polecenia SSH:

IFS='' read -r -d '' SSH_COMMAND <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

ssh user@server "${SSH_COMMAND}"
Dejay Clayton
źródło
+1 półtora roku później! :) naprawdę jasne wyjaśnienie. dobra robota
yaroslavTir
1
Dla mnie (i w żadnym wypadku nie jestem osobą „DevOps”) to działało (używam Jenkinsa). Próbowałem także sugestii „-t -t” i „-T”, ale natknąłem się na problemy z otwartym strumieniem i problemy z niewykonaniem.
Ryan Crews,
2 lata później, naprawdę pomocne
jack-nie
+1 Niesamowite wyjaśnienie. Ale jeśli ostatni fragment kodu (IFS = '' *) stanie się funkcją do wykonywania poleceń zdalnych, to jak przekażesz $ 1 do IFS = '' *? Docent wydaje się w ogóle rozpoznawać zawartość 1 USD.
Cristian Matthias Ambæk
1
@ mklement0 Jasne, w razie potrzeby możesz uciec od ciągów znaków, ale kto chce kłopotać się modyfikowaniem instrukcji skryptu, które możesz kopiować i wklejać z innego skryptu powłoki lub przepełnienia stosu? Elegancja catrozwią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.
Dejay Clayton
63

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.

Andrew Prock
źródło
10
Dla mnie okazało się, że była to kolejna implementacja ssh w ŚCIEŻCE:$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
FelixJongleur42,
i zainstalować opensshto może być droga do systemu Windows: superuser.com/a/301026/260710
Andreas Dietrich
To rozwiązanie działa dla mnie. Po zainstalowaniu openssh problem zniknął.
jdhao
34

Komunikat ostrzegawczy Pseudo-terminal will not be allocated because stdin is not a terminal. wynika z faktu, że nie podano polecenia, sshpodczas gdy stdin jest przekierowywany z dokumentu tutaj. Z powodu braku określonej komendy jako argumentu sshnajpierw 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. Przekierowanie sshstandardowego wejścia z dokumentu tutaj zwykle wymaga podania komendy (np. /bin/sh) Jako argumentu ssh- w takim przypadku domyślnie żadne pty nie zostaną przydzielone na zdalnym hoście.

Ponieważ nie ma żadnych poleceń do wykonania, sshktóre wymagają obecności tty / pty (takiego jak vimlubtop ), -tprzełącznik do sshjest 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 <<\EOTlub cudzysłowy (tj. Lub <<'EOT') wewnątrz dokumentu tutaj, zostanie on rozszerzony przez lokalną powłokę przed jej wykonaniem ssh .... Skutkuje to tym, że zmienne w tym dokumencie pozostaną puste, ponieważ są zdefiniowane tylko w zdalnej powłoce.

Tak więc, jeśli $REL_DIRpowinien być dostępny zarówno dla powłoki lokalnej, jak i zdefiniowany w powłoce zdalnej, $REL_DIRmusi zostać zdefiniowany poza tym dokumentem przed sshpoleceniem ( wersja 1 poniżej); lub, jeśli <<\EOTlub <<'EOT'jest używany, dane wyjściowe sshpolecenia można przypisać, REL_DIRjeśli jedyne wyjście plikussh komendy na standardowe wyjście jest generowane w echo "$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 ).

# version 1

unset DEP_ROOT REL_DIR
DEP_ROOT='/tmp'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR="${DEP_ROOT}/${datestamp}"

ssh localhost /bin/bash <<EOF
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
   echo "creating the root directory" 1>&2
   mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
#echo "$REL_DIR"
exit
EOF

scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"


# version 2

REL_DIR="$(
ssh localhost /bin/bash <<\EOF
DEP_ROOT='/tmp'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR="${DEP_ROOT}/${datestamp}"
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
   echo "creating the root directory" 1>&2
   mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
echo "$REL_DIR"
exit
EOF
)"

scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"


# version 3

heredoc="$(cat <<'EOF'
# -onlcr: prevent the terminal from converting bare line feeds to carriage return/line feed pairs
stty -echo -onlcr
DEP_ROOT='/tmp'
datestamp="$(date +%Y%m%d%H%M%S)"
REL_DIR="${DEP_ROOT}/${datestamp}"
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
   echo "creating the root directory" 1>&2
   mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
echo "$REL_DIR"
stty echo onlcr
exit
EOF
)"

REL_DIR="$(ssh -t localhost "$heredoc")"

scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"
zanco
źródło
5
Dziękuję za bardzo szczegółowe wyjaśnienie, co oznacza ten błąd i dlaczego pojawia się podczas korzystania z heredoc, pomogło mi to właściwie zrozumieć, a nie tylko go obejść.
Dan
29

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:

  • problem z pseudo-terminalem nawet nie powstanie.
  • nie będziesz potrzebował exitinstrukcji 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 sshprojektem i powoduje problemy, które należy następnie obejść.
Czytaj dalej, jeśli chcesz dowiedzieć się więcej.


Opcjonalne informacje podstawowe:

sshMechanizm 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) ( -Timplikowana 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ą -topcji; na przykład:

    • ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'

    • Zauważ, że interaktywny readmonit działa poprawnie tylko z pty, więc ta -topcja 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 sshtworzy interaktywną powłokę - w tym podczas wysyłania poleceń przez stdin , czyli tam zaczyna się problem:

  • W przypadku powłoki interaktywnejssh 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 i ssh ostrzega Cię odpowiednio :
      Pseudo-terminal will not be allocated because stdin is not a terminal.

    • Nawet -topcja, 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 -topcję do tworzenia siłą PTY: ssh -t -t ...albo ssh -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 na readmonit:
        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 -Ti podaj polecenia za pomocą standardowegoexit polecenia końcowego , ale pamiętaj, że jeśli potrzebujesz również interaktywnych funkcji, użycie -ttzamiast tego -Tmoże nie działać.

mklement0
źródło
1
Działa to idealnie, ponieważ -tt sprawiał, że terminal wyświetlał każde polecenie wysłane przez ssh.
Mark E
1
„podwójna opcja -t, aby wymusić utworzenie pty: ssh -t -t ... lub ssh -tt ... pokazuje, że naprawdę, naprawdę masz na myśli.” - ha, ha - dzięki, że to zabawne, ale też poważne - Nie mogę się skupić na podwójnym t, wszystko co wiem to, że gdybym włożył jedno t, to nie woła
DavidC
22

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:

ssh user@server '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'

(Wszystko w jednym olbrzymie ' argumencie wieloliniowym wierszu poleceń).

Komunikat pseudoterminalny jest spowodowany tym, że -tprosi 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?

hmakholm pozostawił Monice
źródło
1
Opcja -t była próbą naprawienia problemu z terminalem Psuedo (nie działał). Próbowałem twojego rozwiązania, pozbyłem się terminalu psuedo, ale teraz po prostu się zawiesza ...
Matthew
4
@ Henning: Czy możesz opracować lub podać link dotyczący wad przekierowywania lub przesyłania strumieniowego do interaktywnego ssh?
Isaac Kleinman,
trochę późno, ale: tutaj nie potrzebujesz pseudo terminala, więc -Tzamiast tego użyj opcji .
Florian Castellane
6

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:

ssh user@machine /bin/bash <<'ENDSSH'
   hostname
ENDSSH

Zamiast tego (daje błąd):

ssh user@machine <<'ENDSSH'
   hostname
ENDSSH

Lub użyj tego:

ssh user@machine /bin/bash < run-command.sh

Zamiast tego (daje błąd):

ssh user@machine < run-command.sh

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.

ssh -t user@machine "$(<run-command.sh)"

A jeśli chcesz także zarejestrować całą sesję w pliku logfile.log:

ssh -t user@machine "$(<run-command.sh)" | tee -a logfile.log
Wadih M.
źródło
0

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

  1. Mx customize-variable (a następnie naciśnij Enter)
  2. tramp-default-method (a następnie ponownie naciśnij Enter)
  3. W polu tekstowym umieść plink, a następnie Zastosuj i zapisz bufor
  4. Ilekroć próbuję uzyskać dostęp do zdalnego serwera, używam teraz Cxf / user @ host: a następnie wprowadzam hasło. Połączenie jest teraz poprawnie wykonane w Emacsie w systemie Windows z moim zdalnym serwerem.
Miguel Rentes
źródło
-3

ssh -t foobar @ localhost yourscript.pl

mxftw
źródło
2
OP używa -trównież, ale w ich konkretnym scenariuszu to nie wystarczy, co skłoniło pytanie do rozpoczęcia.
mklement0