Bash:如何通过ssh发送我自己的自定义函数

时间:2017-07-26 22:27:04

标签: bash ssh-tunnel

我的目标是执行以下操作:

1)检查特定服务器上每个GPU使用的内存量。我用(nvidia-smi --query-gpu=memory.free --format=csv)完成了这个。

2)找到具有最大可用内存的GPU。我用my_cmd()完成了这个。它适用于我当前登录的远程服务器。

3)如果我登录的远程服务器上的最大可用内存小于1000 MiB,请通过SSH连接到群集中的每个其他GPU服务器以查找可用的最大可用内存。这些服务器根据to_check标记。

我目前的问题:

下面的代码在scriptuse命令等cd时有效。

scriptuse mycmd时,以下代码失败。它给了我错误:

bash: my_cmd: command not found

现在,我认为这里存在不止一个问题。首先,我认为我没有正确地向my_cmd命令提供ssh。其次,当我使用my_cmd时,我认为我没有成功地进入其他服务器。

任何人都可以指出错误以及如何修复它吗?

完整的bash脚本如下所示。

#/bin/bash

#https://stackoverflow.com/questions/45313313/nvidia-smi-command-in-bash-vs-in-terminal-for-maximum-of-an-array/45313404#45313404

my_cmd()
{
max_idx=0
max_mem=0
idx=0
{
  read _;                         # discard first line (header)
  while read -r mem _; do         # for each subsequent line, read first word into mem
    if (( mem > max_mem )); then  # compare against maximum mem value seen
      max_mem=$mem                # ...if greater, then update both that max value
      max_idx=$idx                # ...and our stored index value.
    fi
    ((++idx))
  done
} < <(nvidia-smi --query-gpu=memory.free --format=csv)
echo "Maximum memory seen is $max_mem, at processor $idx"
}

tocheck=('4' '5' '6' '7' '8')  #The GPUs to check
it1=1

#scriptuse="my_cmd" 
scriptuse= "cd ~/spatial; pwd; echo $gpuval"

while [ $it1 -lt ${#tocheck[@]} ] ; do #While we stil don't have enough free memory
        echo $it1 
        gpuval=${tocheck[$it1]}
        ssh gpu${gpuval} "${scriptuse}"
        it1=$[it1+1]
done

修改

非常感谢您的帮助,但我的问题尚未解决。我这样做了:

1)从我的bash脚本中删除my_cmd。它现在看起来像这样:

#/bin/bash

#https://stackoverflow.com/questions/45313313/nvidia-smi-command-in-bash-vs-in-terminal-for-maximum-of-an-array/45313404#45313404

tocheck=('4' '5' '6' '7' '8')  #The GPUs to check
it1=1

scriptuse= "cd ~/spatial; echo $gpuval"

while [ $it1 -lt ${#tocheck[@]} ] ; do #While we stil don't have enough free memory
        echo $it1 
        gpuval=${tocheck[$it1]}
        ssh gpu${gpuval} "${scriptuse}" /my_script.sh
        it1=$[it1+1]
done   

2)创建一个名为my_script.sh的单独bash脚本,其中包含my_cmd

#/bin/bash

#https://stackoverflow.com/questions/45313313/nvidia-smi-command-in-bash-vs-in-terminal-for-maximum-of-an-array/45313404#45313404
max_idx=0
max_mem=0
idx=0
{
  read _;                         # discard first line (header)
  while read -r mem _; do         # for each subsequent line, read first word into mem
    if (( mem > max_mem )); then  # compare against maximum mem value seen
      max_mem=$mem                # ...if greater, then update both that max value
      max_idx=$idx                # ...and our stored index value.
    fi
    ((++idx))
  done
} < <(nvidia-smi --query-gpu=memory.free --format=csv)
echo "Maximum memory seen is $max_mem, at processor $idx"

3)跑chmod以确保两个文件都可以运行。

4)确保群集中的所有GPU都存在这两个文件(它们具有公共存储)。

5)Ran ./test_run,这是步骤1中的bash脚本。

我收到错误:

./test_run.sh: line 8: cd ~/spatial; echo : No such file or directory
1
bash: /my_script.sh: No such file or directory
2
bash: /my_script.sh: No such file or directory
3
bash: /my_script.sh: No such file or directory
4
bash: /my_script.sh: No such file or directory

编辑:最终解决方案

感谢下面接受的答案以及评论中的讨论,以下是最终的工作:

1)在上一次编辑中保留my_script

2)文件test_run应如下所示:

#/bin/bash

tocheck=('4' '5' '6' '7' '8')  #The GPUs to check
it1=1

while [ $it1 -lt ${#tocheck[@]} ] ; do #While we still don't have enough free memory
        echo $it1 
        gpuval=${tocheck[$it1]}
        ssh gpu${gpuval} ~/spatial/my_script.sh
        it1=$[it1+1]
done

我认为这样做的原因是群集上的所有GPU都有一个公共存储,因此他们都可以访问/user/spatial

1 个答案:

答案 0 :(得分:2)

您的脚本运行的环境(您的shell)与远程主机运行的环境(远程shell)完全无关。如果在shell中定义函数Public Sub btnLoadEval_Click() Dim ParticipantNumber as String Dim EvaluationDate as Date Dim EvaluationID as Variant If Not IsNull(Me.txtParticipantNumber.Value) And _ Not IsNull(Me.txtEvaluationDate.Value) Then ParticipantNumber = Me.txtParticipantNumber.Value EvaluationDate = Me.txtEvaluationDate.Value EvaluationID = DLookup("EvaluationID", "Evaluations", _ "[ParticipantNumber]=""" & ParticipantNumber & _ """ And [EvaluationDate]=#" & EvaluationDate & "#") If Not IsNull(EvaluationID) Then Call DoCmd.OpenForm("frmEvaluation",,,"[EvaluationID]=" & _ EvaluationID Call DoCmd.Close(acForm, Me.Name, acSaveNo) Else Call MsgBox("No matching evaluation!") End If Else Call MsgBox("Please enter both fields!") End If End Sub ,它将不会通过网络传输到远程主机的shell。

尝试一个更简单的例子:

my_cmd

这根本不是SSH,Bash和Linux / POSIX的设计方式。现在,$ foo() { echo foo; } $ foo foo $ ssh remote-host foo bash: foo: command not found 更新远程环境的某些部分(详见man ssh),但这仅限于某些环境变量,而不是函数。

值得注意的是,远程shell甚至可能与你的shell类型不同(例如你的可能是Bash,但是远程shell可能是Zsh),所以通常不能在{over}之间传输shell函数。 {1}}。

一个更简单,更可靠的选择是创建一个您打算在远程shell上运行的shell脚本(而不是一个函数),并确保远程计算机上存在该脚本。例如:

ssh

修改

ssh

您确定远程主机上存在# Copy the script to the remote host's /tmp directory scp my_cmd.sh remote-host:/tmp # Invoke the script on the remote host $ ssh remote-host /tmp/my_cmd.sh 吗?

./test_run.sh: line 8: cd ~/spatial; echo : No such file or directory

您确定远程主机上存在~/spatial吗?

同样,您的远程主机是一个完全不同的环境。仅仅因为本地计算机上存在文件或目录并不意味着它存在于远程主机上,除非你把它放在那里。

尝试bash: /my_script.sh: No such file or directory /my_script.sh - 我打赌你会看到目录和文件不存在。