采用可变数量参数的 zsh 脚本

采用可变数量参数的 zsh 脚本

我刚刚(迟来的)发现我可以 ssh -t 从一台机器到另一台机器并在那里运行命令。

然后我想到,我应该能够想出一个脚本,通过执行类似的操作来跟踪机器上的日志文件(来自一对)

ssh -t $1 ssh -t $2 tailf /pathtofile/$3/log.log

事实上,如果我手动输入 1,2 和 3,效果就很好。

我的问题是我可能需要在 1,2 或 3 个主机之间跳转才能完成这项工作。

我该如何在 zsh 中执行此操作?我做了一些挖掘,看起来转变可能是我的朋友,但我有点迷失了。

答案1

由于我不是真正的zsh用户,我会写一个sh解决方案(zsh 应该也能够执行)。

一般要点是ssh -t hostname为除最后一个选项之外的每个命令行选项创建一个包含一位的列表,然后将该列表作为命令执行。

#!/bin/sh

argn=$#
i=0

for arg do
   shift
   i=$(( i + 1 ))

   if [ "$i" -lt "$argn" ]; then
       set -- "$@" ssh -t "$arg"
   else
       set -- "$@" "/pathtofile/$arg/log.log"
   fi
done

command "$@"

运行这个作为

sh script.sh alpha beta gamma zeta

它会创建列表

ssh -t alpha ssh -t beta ssh -t gamma /pathtofile/zeta/log.log

脚本中的最后一个命令将作为命令执行。

该列表内置于$@位置参数列表中,它在脚本的开头包含脚本的命令行参数。该循环会跟踪何时遇到原始列表的最后一个元素并对其进行特殊处理。

set命令,当如上使用时,将追加到列表中,并将shift删除列表的第一个元素(我们当前正在处理的元素)。

我确信使用zsh特定的语法可以使这变得更短、更优雅。

答案2

我认为你不能轻易摆脱循环:

cmd=()
for i ($argv[1,-2]) cmd+=(ssh -t $i)
$cmd tailf /pathtofile/$argv[-1]/log.log

严格地说,由于它是您传递给 的 shell 命令行ssh,如果您希望能够支持这些 , 的任意值$1$2您需要引用这些参数并为每个 ssh 添加额外的引用级别。

这里假设所有主机上用户的登录 shell 都是类似 Bourne 的:

cmd=(tailf /pathtofile/$argv[-1]/log.log)
argv[-1]=()
while (($#argv)) {
  cmd=(ssh -t "$argv[-1]" ${(j: :)${(qq)cmd}})
  argv[-1]=()
}

这应该使它在被称为时起作用

that-script host1 host2 'dir with spaces and other nasty characters'

相关内容