
我有一個本地腳本,我想在遠端計算機上運行,而不將其複製到計算機,因此我使用: 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
透過控制其內容的一組受限輸入文件,您可以使用awk
或類似的方法將 stdin 流中的命令替換source
為來源檔案。例如,
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 }' "$@"
這僅匹配第一個單字是“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 X 上運行,我想出了一個可以完成這項工作的函數,儘管我確信你們中的許多人都可以對此進行改進:
# 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 變數中以取代來源語句。