2

У меня есть локальный скрипт, который я хочу запустить на удаленной машине, не копируя его на машину, поэтому я использую: ssh user @ remote <local-script.sh

Это работает, но если я добавляю исходную инструкцию в local-script.sh к исходному другому файлу, например source ./another-local-script.sh , когда local-script.sh запускается на удаленном компьютере, он ищет исходный файл на удаленном , Есть ли способ решить эту проблему, чтобы он сначала разрешал исходные файлы локально?

3 ответа3

2

Вы не можете сделать это прозрачно.

Вы можете изменить ваш bash-скрипт, чтобы получить файлы с вашего локального компьютера, используя обратный туннель, прежде чем искать их, но он не очень чистый.

Гораздо лучше просто перенести все нужные файлы, а затем запустить их так:

scp local-script.sh another-script.sh user@remote
ssh user@remote local-script.sh
0

С ограниченным набором входных файлов, которыми вы управляете содержимым, вы можете использовать awk или аналогичный метод, чтобы заменить source команду в потоке stdin исходным файлом. Например,

desource <local-script.sh | ssh user@remote 

где desource это скрипт

#!/bin/sh
awk '$1=="source" && NF>=2 {
      file = $2; while((getline <file)>0)print $0
      close(file); next
}
{ print }' "$@"

Это просто совпадает со строками, первое слово которых является "источником" и принимает второе слово в качестве файла для вставки. getline читает строку из этого файла (в $ 0) и возвращает 0 в конце файла. Строка print просто копирует несоответствующие строки.

Очевидно, что это сильно ограничено в его применении, и, например, потребуется некоторая работа для повторения, если во включенном файле также есть source команды.


альтернативный getline с переменной вместо $ 0:

while((getline inp <file)>0)print inp

альтернативный скрипт с использованием sed . Он читает файл дважды, поэтому для использования требуется имя файла ( опустите «<», то есть: desource local-script.sh | ssh user@remote)

#!/bin/bash
file=${1?}
cmd=$(  sed -n '/^[ \t]*source[ \t]/{=;s///;p}' <$file |
    sed  '/^[0-9]/{N;s/\n\(.*\)/{r \1;d;}/}' |
    tr ';' '\012' )
sed "$cmd" <$file

Это использует sed первый раз, чтобы соответствовать source строкам, распечатать номер строки (=) и оставить только имя файла (s/// повторно использует тот же шаблон). 2nd sed берет номер строки, добавляет следующую строку (N) и заменяет новую строку и следующее имя файла (. * - остаток строки) на то, что станет командой sed для чтения требуемого файла и удаления исходной строки. tr преобразует точки с запятой в команде в новые строки. Полученная команда передается третьему седу в исходном файле.

0

Спасибо за помощь @ meuh, но так как я не смог заставить ваши примеры работать на Mac OS XI придумала функцию, которая выполняет эту работу, хотя я уверен, что многие из вас могли бы улучшить это:

# desource - substitute source statements in file with contents from sourced file
function desource {
  if [ ! -f "$1" ]; then
    echo "Invalid file: $1"
    return
  fi
  declare tmp
  while read -r line; do
    if [ "${line:0:1}" == '#' ]; then continue; fi
    file=$(echo "$line" | perl -nle 'print $1 if m{(?>source )(.+)}' | sed 's|"||g')
    if [ -n "$file" ]; then
      case "${file:0:1}" in
        '/') ;;
        '~') ;;
        '$') ;;
          *) file="$(cd `dirname $1` && pwd)/$file"
      esac
      file=$(echo "$file" | sed "s|~|$HOME|" | sed "s|\$HOME|$HOME|")
      file="$(cd `dirname $file` && pwd)/$(basename $file)"
      if [ -f "$file" ]; then
        tmp="$tmp\n$(cat $file)"
      else
        echo "Invalid file: $file"
        return
      fi
    else
      tmp="$tmp\n$line"
    fi
  done < "$1"
  echo -e "$tmp"
}

По сути, он читает строку файла построчно, вставляя каждую строку в переменную с именем tmp. Если строка содержит оператор источника, она получает имя файла, разрешая абсолютный путь к файлу (и предполагает, что любые относительные пути будут относиться к переданному скрипту). Он проверяет, существуют ли файлы, а затем добавляет содержимое этих файлов в переменную tmp вместо исходных операторов.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .