
我有 2 個 shell 腳本,file1.sh 和 file2.sh
文件1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
echo "Hello"
文件2.sh
#!/usr/bin/env bash
source file1.sh
echo $var1
echo $var2
當我執行 file2.sh 時,我得到以下輸出
Hello
/data/share
password
但我的預期輸出是
/data/share
password
file1.sh 在 file2.sh 中引用時執行。如何在 file2.sh 中單獨導入變數而不執行 file1.sh?
答案1
當我有一個bash 腳本時,我希望在獲取該腳本時與執行該腳本時有不同的行為(或者換句話說,我希望在不執行任何程式碼的情況下訪問腳本中的資料項)時,我會使用三個選項時間)。這些評論在一定程度上觸及了他們。
選項一
確定何時進行採購並在適當的時間結束“採購”
將腳本分成兩部分,在進入較低的第二個部分之前從腳本中退出
建立具有定義(函數/變數分配/等)的腳本的上半部分,但不直接執行程式碼。
在可執行程式碼部分開始之前,放置邏輯,如果偵測到腳本正在被獲取,則該邏輯將退出腳本。以下程式碼段將執行此操作:
文件1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
# --- End Definitions Section ---
# check if we are being sourced by another script or shell
[[ "${#BASH_SOURCE[@]}" -gt "1" ]] && { return 0; }
# --- Begin Code Execution Section ---
echo "Hello"
echo $var1
echo $var2
文件2.sh
#!/usr/bin/env bash
source file1.sh
echo "$var1"
echo "$var2"
執行 ./file2.sh 的輸出
$ ./file2.sh
/data/share
password
選項二
這個通常只在複雜的情況下使用,對於這個特定的例子來說它是多餘的。我在要獲取來源的文件中創建一個函數,並在該函數中確定呼叫者應該可以使用的內容。在本例中,它是兩個導出的變數。通常,當我有關聯數組時,我會使用此模式,否則幾乎不可能傳遞這些數組。另外,tmp 檔案應該由呼叫者刪除;但在這種情況下我沒有:
文件1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
exportCfg() {
tmpF=$(mktemp)
declare -p var1 var2 > "$tmpF"
echo "$tmpF"
}
if [ "$1" == "export" ]; then
exportCfg;
exit 0;
fi
echo "Hello"
echo $var1
echo $var2
文件2.sh
#!/usr/bin/env bash
source $(./file1.sh export)
echo "$var1"
echo "$var2"
執行file2.sh的輸出與上面相同
選項3
我處理此問題的最後一種常見方法是使用僅包含定義的庫文件,並且沒有在獲取或直接運行時執行的程式碼。這只是劃分程式碼的問題。我有一組 bash“庫”,其中包含常用的函數,並且通常在每個專案的基礎上設置一個小型可獲取的庫來存儲配置資料(常數)。如果該資料包含填滿數組,那麼我也會使用選項 2 的版本。
答案2
如果您的變數都以相同的方式匯出(導出 foo=bar),那麼您可以使用以下方式輕鬆獲取所有這些內容巴什工藝替代特點:
source <(grep '^export .*=' file1.sh)
手冊頁摘錄:
進程替換 在支援命名管道 (FIFO) 或 /dev/fd 命名開啟檔案的方法的系統上支援進程替換。它採用<(列表)或>(列表)的形式。進程清單的輸入或輸出連接到 FIFO 或 /dev/fd 中的某個檔案。該文件的名稱作為擴展結果作為參數傳遞給當前命令。如果使用 >(list) 形式,寫入檔案將為清單提供輸入。如果使用 <(list) 形式,則應讀取作為參數傳遞的檔案以獲得 list 的輸出。