Скрипт Zsh, который принимает переменное количество аргументов

Я только (с опозданием) обнаружил, что могу ssh -t с одной машины на другую и запустить там команду.

Затем мне пришла в голову мысль, что я должен иметь возможность придумать скрипт, который следил за файлом журнала (из пары) на машине, выполняя что-то вроде

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

и действительно, если я положу 1,2 и 3 от руки, это работает просто отлично.

Моя проблема в том, что у меня может быть 1,2 или 3 хоста, чтобы переключаться между ними, чтобы сделать эту работу.

Как бы я сделал это в Zsh? Я немного покопался, и похоже, что Смена может быть моим другом, но я немного растерялся.

Поскольку я не являюсь пользователем 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 синтаксиса.

Я не думаю, что вы можете легко уйти без цикла:

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

Строго говоря, поскольку это командная строка оболочки, которую вы передаете в 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'