我正在尝试编写一个shell脚本,根据我的位置(home / campusA / campusB)自动执行某些启动任务。我去大学并在两个不同的校区(因此是校园A /校园B)上课。我的位置取决于我连接的无线网络。出于此脚本的目的,我们可以假设在调用脚本时我将连接到其中一个网络,并且我的脚本根据对iwconfig
的调用知道我连接到哪个网络。
这就是我想要的:
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
问题在于,campusB的无线网络位于防火墙后面,只有在我username@domain
成功ssh后才能通过互联网访问。成功的ssh之后,我需要保持终端窗口处于活动状态,以便保持互联网访问。如果我关闭终端窗口,我将丢失互联网访问权限(这很糟糕)。
当我尝试执行ssh username@domain
时,脚本会停止,因为我不退出ssh
命令。我不能^C
,这意味着脚本的其余部分永远不会被执行。如果我只是关闭终端窗口试图杀死ssh
会话,我也会遇到同样的问题。
有些谷歌搜索将我带到了subshell
,我使用的是错误或无法用来解决我的问题。那我该如何解决这个问题呢?我很感激任何帮助 - 我已经有一段时间了,我找不到任何有用的东西。如果它有所作为,我宁愿不在脚本中存储我的ssh
密码
此外,对ssh
电话(ssh username@domain &
)进行&ampersanding似乎没有任何好处(有人可以解释原因吗?)
提前谢谢
修改
我必须澄清,ssh连接必须处于活动状态才能让我访问互联网。因此,当我关闭终端窗口时,我需要ssh连接仍然处于活动状态。
答案 0 :(得分:7)
我有一个循环在6台服务器上的脚本,在后台通过ssh调用。在脚本的一部分中,有一个错误的供应商应用程序;应用程序没有正确“放开”连接。 (在后台使用ssh的脚本的其他部分工作正常)。
我发现使用ssh -t -t治愈了这个问题。也许这对你也有帮助。 (一个队友在网上发现了这个,我们花了很多时间,我从未回过头来阅读那篇暗示的文章。我们系统的手册页没有暗示这样的事情是可能的)
希望这有帮助。
答案 1 :(得分:2)
以下是一些可能会有所帮助的想法。
<强>子壳强>
子shell分叉新进程,但不将控制权返回给调用shell。如果你想分叉一个子shell为你做的工作,那么你需要在该行附加一个&
。
(ssh username@domain) &
但这似乎不是使用子shell的令人信服的理由。如果你有一个数字命令,你想按顺序执行,但是与调用shell并行执行,那么也许它是值得的。例如......
(dothis.sh; thenthis.sh; andthislastthingtoo.sh) &
<强>分岔强>
我不确定为什么&
不适合你,但也可能值得研究nohup
。这使命令“免疫”挂起信号。
nohup ssh username@domain
(在末尾尝试使用和不使用&
)
<强>密码强>
不在脚本中存储密码对于任何ssh自动化都是必不可少的。您可以使用公钥加密来实现这一点,这是ssh的固有特性。我不会在这里详细介绍,因为在设置此项目时,所有互联网上都有number of great resources。我强烈建议进一步调查。
如果你选择这条路线,我还建议在“批处理模式”下运行ssh,这将禁用密码查询,如果5分钟后没有响应,将自动与服务器断开连接。
ssh -o 'BatchMode=yes' username@domain
<强>持久性强>
然后,如果你想坚持连接,在bash中运行一些愚蠢的循环! :)
ssh -o 'BatchMode=yes' username@domain "while (( 1 == 1 )); do sleep 60; done"
答案 2 :(得分:2)
您可能想尝试将背景myProg2加倍,以将其与tty:
分离# cf. "Wizard Boot Camp, Part Six: Daemons & Subshells",
# http://www.linux-mag.com/id/5981
(myProg2 &) &
另一种选择可能是使用libslack包中的守护进程工具:
答案 3 :(得分:2)
除了@ shellter的答案之外,我想要精确一些:
@shelter说:
我们系统的手册页没有暗示这样的事情是可能的
在我的系统(Debian 7 GNU/Linux)上,如果我点击:
man -Pcol\ -b ssh| grep -A3 '^ *-t '
我能读到:
-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.
是: 多个-t选项强制tty分配,即使ssh没有本地tty。
这意味着:如果您远程运行需要访问 pseudo terminal
( pty
(例如/dev/pts/0
)的工具,可以使用-t
开关来运行它们。
但是只有从{em> shell控制台(也就是拥有自己的pty)运行ssh
时,这才有效。如果您计划运行它们 shell会话没有控制台,例如后台脚本,您可以使用 Multiple -t 从ssh
强制执行伪tty 分配。
除了@tommy和@geekosaur的答案之外,我还会有一些精确度:
@tommy指向ssh
的非常有用的功能。不确定这与答案有很大关系,但谈到长时间连接,必须清楚地理解这个功能。
建立连接后,ssh
可以(并知道如何)在这一连接中使用它们来驱动很多事情:
-L
允许您驱动到本地计算机/网络的远程TCP连接。 (完整语法为:-L
localip: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为bindind下一个ssh控制台打开 本地unix套接字 。只需打开两个终端窗口。首先在两个窗口中,点击:ssh somewhere
而不是点击netstat -tan | grep :22
或netstat -tan | grep 192.168.1.31:22
(假设 192.168.1.31
是你的onw主机的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
(在两个oppened ssh会话中的任何一个;),你必须看到只有一个 tcp连接。
此类功能可与-L
结合使用,也可能与某些sleep 86399
...
要解决关闭每个非活动TCP连接超过120秒的tcp杀手路由器,我运行:
ssh -M somewhere 'while :;do uptime;sleep 60;done'
即使我没有按键超过两分钟,这也确保连接保持不变。
答案 4 :(得分:1)
&
的问题是ssh失去了对其标准输入(终端)的访问权限,所以当它去读取要发送到另一方的内容时,它会收到错误并退出,或者是{{系统使用kill
来隐式挂起它。 SIGTTIN
和-n
选项用于处理此问题:-f
告诉它不要使用标准输入,-n
告诉它设置任何必要的隧道等,然后关闭终端流。
所以最好的方法就是做
-f
然后在注销前手动终止ssh -L 9999:localhost:9999 -f host & # for some random unused port
。可替换地,
ssh
(重定向是为了确保ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' </dev/null &
无论如何都不会发生。)
当您处于此状态时,您可能希望保存进程ID并将其从SIGTTIN
/ .logout
关闭:
.bash_logout
和ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' < /dev/null & echo $! >~.ssh_pid; chmod 0600 ~/.ssh_pid
:
.bash_logout
那里的额外代码试图避免有人破坏你的if test -f ~/.ssh_pid; then
set -- $(sed -n 's/^\([0-9][0-9]*\)$/\1/p' ~/.ssh_pid)
if [ $# = 1 ]; then
kill $1 >/dev/null 2>&1
fi
rm ~/.ssh_pid
fi
,因为我是一个专业的偏执狂。
(代码未经测试,可能有错字)
答案 5 :(得分:0)
自从我使用ssh已经有一段时间了,我现在无法测试它,但是你尝试过-f开关吗?
ssh -f username@domain
手册页说背景ssh。不确定为什么&
不起作用,但我猜它是把它解释为在远程机器上运行的命令。
答案 6 :(得分:0)
也许screen + ssh也适合这个账单?
类似的东西:
screen -d -m -S sessionName cmd
screen -d -m -S sessionName cmd &
# reconnect with
screen -r sessionName