bash 为 SSH 生成子 shell 并继续执行程序流程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5185717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spawn subshell for SSH and continue with program flow
提问by inspectorG4dget
I'm trying to write a shell script that automates certain startup tasks based on my location (home/campusA/campusB). I go to University and take classes in two different campuses (hence campusA/campusB). My location is determined by which wireless network I'm connected to. For the purposes of this script, we can assume that I will be connected to one of these networks when the script is called and my script knows which one I'm connected to based on a call to iwconfig.
我正在尝试编写一个 shell 脚本,根据我的位置(home/campusA/campusB)自动执行某些启动任务。我上大学并在两个不同的校区上课(因此是campusA/campusB)。我的位置取决于我连接到的无线网络。出于此脚本的目的,我们可以假设在调用脚本时我将连接到这些网络之一,并且我的脚本根据对iwconfig.
This is what I want it to do:
这就是我想要它做的:
cat file1 > file2 # always do this, regardless of where I am
if Im at home:
start tweetdeck, thunderbird, skype
else if Im at campusA:
activate the login script # I need to login on a webform before I get internet access.
# I have written a script to automate this.
# Wait for this script to finish before doing anything else
myProg2 & # I want myProg2 running in the background until I shutdown my computer.
else if Im at campusB:
ssh username@domain # this is the problematic line
myProg2 & # I want myProg2 running in the background until I shutdown my computer.
start tweetdeck, thunderbird
close the terminal with the "exit" command
The problem is that campusB's wireless network is behind a firewall, which grants me internet access ONLY after I successfully ssh by username@domain. After a successful ssh, I need to keep the terminal window active in order to hold keep the internet access. If I close the terminal window, I lose internet access (this is bad).
问题是campusB 的无线网络在防火墙后面,只有在我成功通过 ssh 后才允许我访问互联网username@domain。ssh 成功后,我需要保持终端窗口处于活动状态以保持互联网访问。如果我关闭终端窗口,我将无法访问互联网(这很糟糕)。
When I try doing just ssh username@domain, the script stops because I don't exit the sshcommand. I can't ^Cout of it, which means that the rest of the script is never executed. I also have the same problem if I just close the terminal window in an attempt to kill the sshsession.
当我尝试执行 just 时ssh username@domain,脚本停止,因为我没有退出ssh命令。我无法^C摆脱它,这意味着脚本的其余部分永远不会执行。如果我只是关闭终端窗口以试图终止ssh会话,我也会遇到同样的问题。
Some googling brought me to subshell, which I'm either using wrong or can't use to solve my problem. So how should I go about solving this problem? I'd appreciate any help - I've been at this for a while now and am unable to find anything helpful. If it makes a difference, I'd rather not store my sshpassword in the script
一些谷歌搜索将我带到subshell,我要么使用错误,要么无法用来解决我的问题。那么我应该如何解决这个问题呢?我很感激任何帮助 - 我已经在这里工作了一段时间,但找不到任何有用的东西。如果它有所作为,我宁愿不将我的ssh密码存储在脚本中
Further, ampersanding the sshcall (ssh username@domain &) doesn't seem to do any good (can anyone explain why?)
此外,在ssh调用 ( ssh username@domain &) 上加上&符号似乎没有任何好处(谁能解释为什么?)
Thank you in advance
先感谢您
EDIT
编辑
I must clarify, that the ssh connection has to be active in order for me to have internet access. Thus, when I close the terminal window, I need the ssh connection to still be active.
我必须澄清,ssh 连接必须处于活动状态,我才能访问互联网。因此,当我关闭终端窗口时,我需要 ssh 连接仍然处于活动状态。
回答by shellter
I had a script that looped on 6 servers, calling via ssh in the background. In 1 part of the script, there was a mis-behaving vendor application; the application didn't 'let go' of the connection properly. (other parts of the script using ssh in background worked fine).
我有一个在 6 个服务器上循环的脚本,在后台通过 ssh 调用。在脚本的一部分中,有一个行为不端的供应商应用程序;应用程序没有正确地“放开”连接。(在后台使用 ssh 的脚本的其他部分工作正常)。
I found that using ssh -t -t cured the problem. Maybe this can help you too. (a teammate found this on the web, and we had spent so much time, I never went back to read the article that suggested this. The man page on our system gave no hint that such a thing was possible)
我发现使用 ssh -t -t 解决了这个问题。也许这也可以帮助你。(一个队友在网上发现了这个,我们花了这么多时间,我再也没有回去阅读建议这个的文章。我们系统上的手册页没有暗示这样的事情是可能的)
Hope this helps.
希望这可以帮助。
回答by perden
Here's a few thoughts that might help.
这里有一些想法可能会有所帮助。
Sub-shells
子壳
Sub-shells fork new processes, but don't return control to the calling shell. If you want to fork a sub-shell to do the work for you, then you'll need to append a &to the line.
子 shell 派生新进程,但不将控制权返回给调用 shell。如果你想 fork 一个子 shell 来为你完成工作,那么你需要&在行中附加 a 。
(ssh username@domain) &
(ssh username@domain) &
But this doesn't look like a compelling reason to use a sub-shell. If you had a number commands you wanted to execute in order from each other, yet in parallel from the calling shell, then maybe it would be worth it. For example...
但这看起来并不是使用子 shell 的令人信服的理由。如果您有多个命令要按顺序执行,但要从调用 shell 并行执行,那么也许值得。例如...
(dothis.sh; thenthis.sh; andthislastthingtoo.sh) &
(dothis.sh; thenthis.sh; andthislastthingtoo.sh) &
Forking
分叉
I'm not sure why &isn't working for you, but it may be worth looking into nohupas well. This makes the command "immune" to hang up signals.
我不确定为什么&不适合你,但它也可能值得研究nohup。这使得命令“免疫”挂断信号。
nohup ssh username@domain(try with and without the &at the end)
nohup ssh username@domain(尝试&在最后有和没有)
Passwords
密码
Not storing passwords in the script is essential for any ssh automation. You can accomplish that using public key cryptography which is an inherent feature of ssh. I wont go into the details here because there are a numberofgreatresourcesall across the interwebs on setting this up. I strongly suggest investigating this further.
不在脚本中存储密码对于任何 ssh 自动化都是必不可少的。您可以使用公钥加密来实现这一点,这是 ssh 的一个固有特性。因为有我不会详谈这里数量的巨大资源全部横跨interwebs设置此功能。我强烈建议进一步调查此事。
- HOWTO: set up ssh keys- Paul Keck, 2001
- SSH Keys- archlinux.org
- SSH with authentication key instead of password- Debian Administration
- Secure Shell- Wikipedia, the free encyclopedia
- 如何:设置 ssh 密钥- Paul Keck,2001
- SSH 密钥- archlinux.org
- 使用身份验证密钥而不是密码的 SSH- Debian 管理
- Secure Shell- 维基百科,免费的百科全书
If you do go this route, I also suggest running ssh in "batch mode" which will disable password querying and will automatically disconnect from the server if it becomes unresponsive after 5 minutes.
如果你确实走这条路,我还建议在“批处理模式”下运行 ssh,这将禁用密码查询,如果 5 分钟后服务器没有响应,它将自动断开与服务器的连接。
ssh -o 'BatchMode=yes' username@domain
ssh -o 'BatchMode=yes' username@domain
Persistence
坚持
Then if you want to persist the connection, run some silly loop in bash! :)
然后,如果您想保持连接,请在 bash 中运行一些愚蠢的循环!:)
ssh -o 'BatchMode=yes' username@domain "while (( 1 == 1 )); do sleep 60; done"
ssh -o 'BatchMode=yes' username@domain "while (( 1 == 1 )); do sleep 60; done"
回答by gerd
You may want to try to double background myProg2 to detach it from the tty:
您可能想尝试将背景 myProg2 加倍以将其与 tty 分离:
# cf. "Wizard Boot Camp, Part Six: Daemons & Subshells",
# http://www.linux-mag.com/id/5981
(myProg2 &) &
Another option may be to use the daemon tool from the libslack package:
另一种选择可能是使用 libslack 包中的守护程序工具:
回答by F. Hauri
Having a ssh with pseudy tty on background shell
在后台外壳上使用带有伪 tty 的 ssh
In addition to @shellter's answer, I would like make some precision:
除了@shellter 的回答之外,我还想做出一些精确的说明:
where @shelter said:
@shelter 说:
The man page on our system gave no hint that such a thing was possible
我们系统上的手册页没有暗示这种事情是可能的
On mysystem (Debian 7 GNU/Linux), if I hit:
在我的系统(Debian 7 GNU/Linux)上,如果我点击:
man -Pcol\ -b ssh| grep -A3 '^ *-t '
I could read:
我可以读:
-t Force pseudo-tty allocation. This can be used to execute arbi‐
trary 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.
Yes: Multiple -t options force tty allocation, even if ssh has no local tty.
是:多个 -t 选项强制 tty 分配,即使 ssh 没有本地 tty。
This mean: If you remotely run a tool that require access to pseudo terminal( ptylike /dev/pts/0), you could run them by using -tswitch.
这意味着:如果您远程运行需要访问权限的工具pseudo terminal(pty例如/dev/pts/0),您可以使用-tswitch来运行它们。
But this would work only if sshis run from a shell console(aka having his own pty). If you plan to run them is shell session withoutconsole, like background scripts, you may use Multiple -tto enforce pseudo ttyallocation from ssh.
但这只有在ssh从shell 控制台运行时才有效(也就是拥有自己的 pty)。如果计划运行它们是shell会话没有控制台,像后台脚本,您可以使用多个-t执行伪TTY的分配ssh。
Multiple ssh shell on one ssh connection
一个 ssh 连接上的多个 ssh shell
In addition to answers from @tommy and @geekosaur, I would make some precision:
除了@tommy 和@geekosaur 的回答之外,我还会做一些精确的说明:
@tommy point to a very interstingfeature of ssh. Not sure this have a lot to do with answer, but speaking around long time connection, this feature has to be clearly understood.
@tommy指向一个非常野趣的特点ssh。不确定这与答案有很大关系,但是谈到长时间连接,必须清楚地了解此功能。
Once a connection is established, sshcould (and know how to) use them to drive a lot of thing in this one connection:
一旦建立了连接,ssh就可以(并且知道如何)使用它们在这个连接中驱动很多事情:
-Llet you drive remote TCP connections to local machines/network. (full syntax is:-Llocalip:localport:distip:distport) where localip could be specified to permit other hosts from same local domain to access same tcp bind, and distip could by any host from distant network ( not only localhost) sample:-L192.168.1.31:8443:google.com:443permit any host from local domain to reach googlethrough your host:http://192.168.1.31:8443-RSame remarks in reverse way!-MTell ssh to open a local unix socketfor bindind next ssh consoles. Simply open two terminal window. First in both window, hit:ssh somewherethan hitnetstat -tan | grep :22ornetstat -tan | grep 192.168.1.31:22(assuming192.168.1.31is your onw host's ip)Than compare close all your ssh session and in first terminal, hit:
ssh -M somewhereand in second, simplyssh somewhere. you may see in second terminal:$ ssh somewhere + ssh somewhere Last login: Mon Feb 3 08:58:01 2014 from elsewhereIf now you hit
netstat -tan | grep 192.168.1.31:22(on any of two oppened ssh session;) you must see that there is only onetcp connection.This kind of features could be used in combination with
-Land maybe somesleep 86399...To work around a tcp killer router that close every inactive TCP connection from more than 120 seconds, I run:
ssh -M somewhere 'while :;do uptime;sleep 60;done'This ensure connection stay up even if I dont hit a key for more than two minutes.
-L让您将远程 TCP 连接驱动到本地机器/网络。(完整的语法是-Llocalip:localport:distip:distport:)其中可以指定 localip 以允许来自同一本地域的其他主机访问相同的 tcp 绑定,并且 distip 可以由来自远程网络的任何主机(不仅是localhost)示例:-L192.168.1.31:8443:google.com:443允许来自本地域的任何主机访问google通过您的主机:http://192.168.1.31:8443-R反过来说同样的话!-M告诉 ssh 打开一个本地 unix 套接字用于绑定下一个 ssh 控制台。只需打开两个终端窗口。首先在两个窗口中,点击:ssh somewhere比点击netstat -tan | grep :22或netstat -tan | grep 192.168.1.31:22(假设192.168.1.31是您的主机的 IP)比较关闭所有 ssh 会话并在第一个终端中,点击:
ssh -M somewhere,第二个,简单地ssh somewhere. 您可能会在第二个终端中看到:$ ssh somewhere + ssh somewhere Last login: Mon Feb 3 08:58:01 2014 from elsewhere如果现在您点击
netstat -tan | grep 192.168.1.31:22(在两个打开的 ssh 会话中的任何一个;)您必须看到只有一个tcp 连接。这种功能可以结合使用
-L,也许还有一些sleep 86399......为了解决关闭每个非活动 TCP 连接超过 120 秒的 tcp 杀手路由器,我运行:
ssh -M somewhere 'while :;do uptime;sleep 60;done'这可确保即使我超过两分钟没有按下任何键也能保持连接。
回答by geekosaur
The problem with &is that ssh loses access to its standard input (the terminal), so when it goes to read something to send to the other side it either gets an error and exits, or is killed by the system with SIGTTINwhich will implicitly suspend it. The -nand -foptions are used to deal with this: -ntells it not to use standard input, -ftells it to set up any necessary tunnels etc., then close the terminal stream.
问题&在于 ssh 无法访问其标准输入(终端),因此当它读取某些内容以发送到另一端时,它要么出错并退出,要么被kill系统 edSIGTTIN隐式挂起它. 在-n和-f选项用来对付这样的: -n告诉它不要使用标准输入,-f告诉它要建立必要的隧道等,然后关闭终端流。
So the best way to do this is probably to do
所以最好的方法可能是做
ssh -L 9999:localhost:9999 -f host & # for some random unused port
and then manually kill the sshbefore logout. Alternately,
然后手动杀死ssh注销前。交替,
ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' </dev/null &
(The redirection is to make sure the SIGTTINdoesn't happen anyway.)
(重定向是为了确保SIGTTIN无论如何都不会发生。)
While you're at it, you may want to save the process ID and shut it down from your .logout/.bash_logout:
在此过程中,您可能希望保存进程 ID 并从.logout/关闭它.bash_logout:
ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' < /dev/null & echo $! >~.ssh_pid; chmod 0600 ~/.ssh_pid
and in .bash_logout:
并在.bash_logout:
if test -f ~/.ssh_pid; then
set -- $(sed -n 's/^\([0-9][0-9]*\)$//p' ~/.ssh_pid)
if [ $# = 1 ]; then
kill >/dev/null 2>&1
fi
rm ~/.ssh_pid
fi
The extra code there attempts to avoid someone sabotaging your ~/.ssh_pid, because I'm a professional paranoid.
那里的额外代码试图避免有人破坏你的~/.ssh_pid,因为我是一个专业的偏执狂。
(Code untested and may have typoes)
(代码未经测试,可能有错别字)
回答by tommy
Maybe screen + ssh would fit the bill as well?
也许 screen + ssh 也符合要求?
Something like:
就像是:
screen -d -m -S sessionName cmd
screen -d -m -S sessionName cmd &
# reconnect with
screen -r sessionName
回答by OpenSauce
It's been a while since I've used ssh, and I can't test it right now, but have you tried the -f switch?
自从我使用 ssh 已经有一段时间了,我现在无法对其进行测试,但是您是否尝试过 -f 开关?
ssh -f username@domain
The man page says it backgrounds ssh. Not sure why &wouldn't work, but I guess it's interpreting it as a command to be run on the remote machine.
手册页说它是 ssh 的背景。不知道为什么&不起作用,但我想它将它解释为要在远程机器上运行的命令。

