
컴퓨터에 복사하지 않고 원격 컴퓨터에서 실행하려는 로컬 스크립트가 있으므로 다음을 사용하고 있습니다. ssh user@remote < local-script.sh
이것은 작동하지만 다른 파일을 소스로 사용하기 위해 local-script.sh에 소스 문을 추가하면 source ./another-local-script.sh
local-script.sh가 원격에서 실행될 때 원격에서 소스 파일을 찾습니다. 소스 파일을 로컬에서 먼저 확인하도록 이 문제를 해결할 수 있는 방법이 있습니까?
답변1
이 작업을 투명하게 수행할 수는 없습니다.
소싱하기 전에 bash 스크립트를 조작하여 역방향 터널을 사용하여 로컬 시스템에서 파일을 가져올 수 있지만 그다지 깨끗하지는 않습니다.
훨씬 더 나은 방법은 필요한 모든 파일을 전송한 후 다음과 같이 실행하는 것입니다.
scp local-script.sh another-script.sh user@remote
ssh user@remote local-script.sh
답변2
내용을 제어하는 제한된 입력 파일 세트를 사용하면 stdin 스트림의 명령을 소스 파일로 awk
대체하는 데 유사한 기능을 사용할 수 있습니다. source
예를 들어,
desource <local-script.sh | ssh user@remote
리소스는 스크립트입니다.
#!/bin/sh
awk '$1=="source" && NF>=2 {
file = $2; while((getline <file)>0)print $0
close(file); next
}
{ print }' "$@"
이는 첫 번째 단어가 "source"인 행과 일치하고 두 번째 단어를 삽입할 파일로 사용합니다. getline
해당 파일에서 한 줄을 $0으로 읽고 파일 끝에서 0을 반환합니다. 라인은 print
일치하지 않는 라인을 통해 복사됩니다.
분명히 이는 해당 응용 프로그램에서 매우 제한적이며, 예를 들어 포함된 파일에도
source
명령이 있는 경우 반복하려면 약간의 작업이 필요합니다.
$0 대신 변수를 사용하는 대체 getline:
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/// 동일한 패턴을 재사용함). 두 번째 sed는 줄 번호를 가져와 다음 줄(N)을 추가하고 줄 바꿈과 다음 파일 이름(.*는 나머지 줄)을 대체하여 원하는 파일을 읽고 원래 줄을 삭제하는 sed 명령이 됩니다. tr
명령의 세미콜론을 줄 바꿈으로 변환합니다 . 결과 명령은 원본 파일의 세 번째 sed에 제공됩니다.
답변3
@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 변수에 추가합니다.