使用 Linux、bash 和 OpenSSH,我可以通过至少三种方式在远程主机上执行 shell 脚本:
# Method 1: Script is never stored on the remote host
ssh <username>@<hostname> 'bash -s' < myShellScript
# Method 2: Script is permanently stored on the remote host
ssh <username>@<hostname> 'myShellScript'
# Method 3: Copy script to the remote host, execute it, and delete it
scp myShellScript <username>@<hostname>:~
ssh <username>@<hostname> 'myShellScript; rm -f myShellScript'
我更喜欢方法 1 而不是方法 2,因为它可以防止脚本副本的激增以及相关的维护麻烦。
我更喜欢方法 1 而不是方法 3,因为它比复制和删除脚本更快并且通常“更干净”。
但是,如果我要成功实现坚持方法 1 的目标,就需要解决一个问题。我的 Shell 脚本采用以下形式:
#!/bin/bash
# Do stuff...
myProgram input myProgramInputFile
# Do more stuff...
这里,我的程序是一个标准实用程序,可用于我可能想要交互的所有远程主机。但是,我的程序输入文件是仅存在于我的本地计算机上的常规文件。它不存在于任何远程主机上。
我希望能够“穿得暖和”我的 Shell 脚本和我的程序输入文件将其合并为一个漂亮的“包”,通过 SSH 在远程主机上执行,而无需在远程文件系统上明确存储任何内容(无论是永久的还是临时的)。这可能吗?
答案1
我宁愿至少复制myProgramInputFile
(方法 3类似);我认为它会更坚固。然而,有一种方法可以让它与鞋底一起工作方法 1。
我的方法
我建议您制作一个(本地)脚本,将适当的文件复制到远程端,触发执行并在之后进行清理。
我们将需要三个本地文件:myLocalScript
(可执行文件)myRemoteScript
和myProgramInputFile
。
内容myLocalScript
:
#!/bin/bash
# step 1: storing command line arguments to meaningful names
ssh_command="ssh $1"
script="$2"
input="$3"
# step 2: creating remote temporary file
remote_input=$($ssh_command 'mktemp')
# step 3: copying the content of local input file to the remote temporary file
cat "$input" | $ssh_command "cat > \"$remote_input\""
# step 4: sourcing the script to the remote side
$ssh_command "input=\"$remote_input\" bash -s" < "$script"
# step 5: removing the remote temporary file
$ssh_command "rm \"$remote_input\""
myRemoteScript
将如下所示:
# shebang is not needed, this script will effectively be sourced
# Do stuff…
myProgram input "$input"
# Do more stuff…
文件myProgramInputFile
(本地)和myProgram
(远程)将保持当前设置中的原样。
本地用法:
./myLocalScript <username>@<hostname> myRemoteScript myProgramInputFile
技术说明和解释:
- 在第2步
mktemp
在远程计算机上的临时目录中创建一个文件。我们不想使用,mktemp -u
以避免其他人实际上在我们之间创建了同名文件的情况第2步和步骤 3。 - 在步骤 3
scp
如果我们使用,我们可以使用mktemp -u
。远程临时文件已经存在,因此我们使用cat
来写入它。 - 在步骤4
myRemoteScript
需要知道远程计算机上下文中临时文件的路径。这就是我们将本地$remote_input
作为input
变量传递给远程的原因bash
。这样,当myRemoteScript
输入到所述时bash
,其中的$input
指示临时文件路径。 - 如果我们打破远程
bash
(例如,使用单个Ctrl+ c)那么myLocalScript
将前进到步骤 5并无论如何都要进行清洁。这就是为什么清洁不在结束时进行的原因myRemoteScript
,尽管它可以在结束时进行。
唯一方法 1方法
谢谢此处有文件您可以嵌入myProgramInputFile
到myShellScript
。
这将很容易如果myProgramInputFile
是文本文件并且myProgram
可以读取stdin
(也许用myProgram input -
语法?或者也许input
省略了什么时候?)
myShellScript
将如下所示:
# shebang is not needed, this script will effectively be sourced
# Do stuff…
myProgram input - <<"EOF"
The content of myProgramInputFile is pasted here,
it continues here
and here,
and so on.
EOF
# Do more stuff…
然后我们将像下面这样运行它方法 1:
ssh <username>@<hostname> 'bash -s' < myShellScript
如果myProgram
无法阅读stdin
但是远程系统允许您使用,那么我们应该像这样/proc/self/
写入关键的一行:myShellScript
myProgram input /proc/self/fd/0 <<"EOF"
如果myProgramInputFile
超过文本然后我们应该在本地对其进行编码(参见uuencode
、base64
)并在远程端进行解码。我们还应该检查EOF
编码文本中是否没有行,如果是,则更改此处的文档分隔符。请注意,在这种情况下base64
不使用_
是E_O_F
完全安全的(但使用 可能不行uuencode
,我不知道)。
作为一个概念验证我将 Super User favicon 压缩,用 编码base64
并嵌入到脚本中。我选择用 来演示/proc/self/fd/0
方法cp
,但可能也一样cat > ~/SUfavicon.ico
好;或者gzip -cd > ~/SUfavicon.ico
在管道中更早一点更好。
当然,在您的情况下,应该用 来myProgram
代替cp
。
在这种情况下,注意{}
很重要,它们使得此处的文档被定向到base64 -d
。
# shebang is not needed, this script will effectively be sourced
{ base64 -d | gzip -cd | cp /proc/self/fd/0 ~/SUfavicon.ico ; } <<"E_O_F"
H4sICE3cXFkCA2Zhdmljb24uaWNvAO2XT2jTUBzHf2lnO1HXIAiKYHuSIYhzoCgIlV1EdtDDTmMg
CIKI7DQ9Taq71Il0VfBSmP9QmKziYRd3GCoqu40JIhtiB7sIOm1AcJ1r8/y+5bXEZ1KbtH07uMCH
3/pLvvm8lzYvC5FGAdJ1Qo3R+RaivUQUi1mfx9BPodeOns77ZPXXthZy25IgX2bbZkrz5uIjmvz+
lPKCBZAEmkOeH8/ABOjXt1AXb86NUg+Ov/AtSwOoy6gl1PYq+UtuA0RuHjCw32d+Dn6znrzwH/SZ
fy78w6gBr3lkOpH9DPg53nrNLzykVpzjDp8DatFLfrCXArkHlBLzfwcOgUANed4zE320/es4fRDz
7/Zw/XiP3TxHm5bGK9f/mJ/rv5StfP++8sjmxLU/7DWP7FHkiqhfUNuq5J+AM7h/jvDm/F06geOv
AJ5bBX0uwyvnTV5x/2bE/fsGmQK8U6hdTsGhsMXItI3XNq5hPQlbVPZjtRiKgKi1zvDV5bh9ndH/
9jDG/iCi6yuAVaOcXczuYy78ALPgOtjhND/Za/OzBvjtfARb19HP6a3Dr5GHDS4NvJL8g3795GOD
77bkv6rYn97w/9f+Ecl/Q7G/X/K/B0GF/t1gRRpDBoRU+MUYLjusgznR39lsvxjDAFh2GMdPFX4x
hrNOzwQF178NPHNwl8BEk39//Bk06eC9BfY06veH/Z1gFNwHKRAW/pMO8+5p9P2H/Wnp+A7hT0ru
qWasP1X88vqbbpL/FJgBs+AF0FX6PTx/Nvzr6x9W7B+T/BdV+fm7BshL/g6F/ozknq7z/Uur0bsL
PJbcv8ABRe9/Jekz///ntNt4m/z+N+M27xr8qz79n8A90M2fv//6vso+I0QJEF8jYcQNVnAjCiIG
KwYNZgIWtP4uhA2zNQriFRzz/NwwJF5yHzNCGgiy3wHSerE2FQAA
E_O_F
像以前一样运行:
ssh <username>@<hostname> 'bash -s' < myShellScript
然后您将~/SUfavicon.ico
在远程机器上找到。