Для каждого каталога по пути выполнить сценарий оболочки из этого каталога (, если найти -execdir не подходит)

Вы не можете сделать это с помощью простого удаленного -- -удаленного SCP [1].

Вместо этого подключитесь по ssh к 1-му удаленному хосту и оттуда запустите scp с аргументом порта:

ssh -p 2222 ruser1@rhost1 scp -P 2222 /rpath/1 ruser2@rhost2:/rpath/2

Если вы хотите делать именно то, что делает scp, вы также можете добавить опции -n -x -oClearAllForwardings=yesк ssh, хотя обычно это не требуется.


[1] :более новые версии scpподдерживают спецификацию uri (, включающую порт )вместо host:path, но только при использовании опции -3(«проходить через локальный хост» ).

Вероятно, вы могли бы использовать

scp -3 -P 2222 ruser1@rhost1:/rpath/1 scp://ruser2@rhost2:2222//rpath/2

(обратите внимание, что /после host[:port]не является частью пути --scp://user@host/file, будет ссылаться на ./fileв домашнем каталоге user).

Но копирование через локальный хост происходит медленнее, и, по моему опыту, оно скроет ошибки. Например, это не будет печатать никаких сообщений об ошибках, несмотря на невозможность создать файл /foo/bar/baz:

.

scp -3 localhost:.bashrc localhost:/foo/bar/baz

Я не углублялся в это --просто избегал этого;-)


Если кого-то все это не убедило, они могут посмотреть исходный код:

void
toremote(char *targ, int argc, char **argv)
{
  ...
                } else if (host) {      /* standard remote to remote */
                        if (tport != -1 && tport != SSH_DEFAULT_PORT) {
                                /* This would require the remote support URIs */
                                fatal("target port not supported with two "
                                    "remote hosts without the -3 option");
                        }

Обратите внимание, что переменная tportустанавливается только путем синтаксического анализа scp://uri и просто не существует в версиях старше 7.6p1 (Октябрь 2017 ).

0
18.09.2021, 22:44
2 ответа

Два варианта вашего кода, каждый из которых передает специальные значения в строчный скрипт -, который вы вызываете изfind:

#!/bin/sh

mpath=$1
fn_name=$2
fn_arg=$3

find "$mpath" -type d -exec sh -c '
    cd "$3" && /path/to/my/script.sh "$1" "$2"' sh "$fn_name" "$fn_arg" {} \;

Когда каталог найден, findпросто передает значения двух переменных fn_nameи fn_argв сценарий sh -cв качестве двух первых аргументов перед аргументом пути к каталогу. Внутри скрипта мы используем два первых аргумента в качестве аргументов вашего скрипта, а третий — в качестве пути к каталогу cd.

Обратите внимание, что $0будет содержать строку sh. Оболочка будет использовать эту (произвольную )строку в любых сообщениях об ошибках, которые она может выдать (вы показываете пример этого в своем вопросе ). Значение $0является , а не частью списка позиционных параметров.

Другой вариант, который вызывает внутристрочный скрипт -с максимально возможным количеством путей к каталогам одновременно:

#!/bin/sh

mpath=$1
fn_name=$2
fn_arg=$3

find "$mpath" -type d -exec sh -c '
    fn=$1 arg=$2; shift 2
    for dirpath do
        ( cd "$dirpath" && /path/to/my/script.sh "$fn" "$arg" )
    done' sh "$fn_name" "$fn_arg" {} +

Изменив \;на +в конце команды find, мы вызываем sh -cс пакетами найденных путей к каталогам. Сценарий строки -затем должен перебирать их и вызывать ваш сценарий для каждого по очереди.

Скрипт строки -начинается с выбора имени функции и аргумента из списка позиционных параметров и смещения их из этого списка. Затем он перебирает оставшиеся аргументы и вызывает cdи ваш скрипт для каждого.Ниже приведен строчный скрипт -со вставленным небольшим количеством воздуха :

.
fn=$1    # 1st argument from find
arg=$2   # 2nd argument from find
shift 2  # remove them from the list

# Iterate over the remaining arguments
for dirpath do
    ( cd "$dirpath" && /path/to/my/script.sh "$fn" "$arg" )
done

Я запускаю тело цикла в оболочке sub -, чтобы избежать «cdвозврата» каждый раз после запуска сценария.

Здесь я использую sh, а не bash, так как shничего не нужно для запуска этого кода. Кроме того, показанные здесь команды findиспользуют только стандартные функции.

4
19.09.2021, 08:07

Вот мое предложенное (и рабочее )решение:

#!/bin/bash
function_name=$1
mpath="$2"
marg=$3

while IFS= read -r -d '' sdir
do
  cd "$sdir"
  /path/to/my/script.sh "$function_name" "$marg"
done <   <(find "$mpath" -type d -print0)

Изменить :В ответ на комментарии, это решение не работает с относительными путями.

-1
19.09.2021, 00:23

Теги

Похожие вопросы