Bash

bash 腳本 - 從標準輸入讀取 tarball

  • March 10, 2014

我有一個任務需要編寫腳本,我覺得應該非常簡單,但實際上我過得很艱難。

我有一個簡短的 bash 腳本,它採用 tarball 形式的特定類型的應用程序並建構它。目前它只需要兩個命令行參數:應用程序的名稱和 tarball 的位置。但是我正準備在多主機系統上部署建構腳本,相反,我希望這個腳本在標準輸入上獲取應用程序壓縮包,這將通過 ssh 管道傳輸。例如,這是我想呼叫腳本的方式:

ssh build-host "/usr/local/bin/build-app.sh myapp" < /tmp/myapp.tar.gz

當像這樣呼叫時,建構腳本將嘗試建構一個名為“myapp”的應用程序。

我希望建構腳本在讀取 tarball 之前執行一些完整性檢查。此外,如果健全性檢查失敗,它應該正常退出。所以這是我第一次嘗試建構腳本的要點:

#!/bin/bash

appname=$1

# example sanity check
if [ ! -d "/apps/$appname" ]; then
   mkdir "/apps/$appname"
else
   echo "Error! The app already has been built."
   exit 1
fi

# more sanity checks...

# if passed all tests, then read stdin into tarfile
cat > "/apps/$appname/app.tar.gz"

# build app ...

這幾乎可以工作。問題是我無法弄清楚如何在 bash 腳本中途從標準輸入讀取。這個cat > file技巧只有在我把它放在腳本的第一行時才有效。但我不想那樣做。在腳本的第一行,沒有執行任何健全性檢查,甚至無法確定將 tarfile 放在哪裡。我可能同時執行多個腳本實例,並且沒有避免衝突的好方法。

(除了cat > file,我還嘗試< /dev/stdin > file了類似結果非常相似的技巧。)

所以我也嘗試了以下方法:

#!/bin/bash

tarball="$(cat)"
appname="$1"

# example sanity check
if [ ! -d "/apps/$appname" ]; then
   mkdir "/apps/$appname"
else
   echo "Error! The app already has been built."
   exit 1
fi

# more sanity checks...

# if passed all tests, then read stdin into tarfile
echo -n "$tarball" > "/apps/$appname/app.tar.gz"

# build app ...

但這也很成問題,原因有兩個。首先,它沒有用。echo,即使帶有-n標誌,似乎也不是為二進制數據設計的,並且生成的 tarfile 已損壞。其次,這需要將整個 tarball 儲存為變數作為第一步。這不僅比預期的要慢,即使對於 5MB 的測試 tarball 也是如此,而且還可能意味著高記憶體消耗,尤其是對於我可能要處理的大型應用程序。

我喜歡從標準輸入讀取 tarfile 的想法。這意味著 bash 腳本可以在需要中止時簡單地關閉管道,並且它可以允許 bash 腳本決定將所有應用程序 tarball 放在哪裡,而不是呼叫建構腳本的原始版本,後者看起來像這樣:

scp /tmp/myapp.tar.gz build-host:/tmp/
ssh build-host /usr/local/bin/build-app.sh myapp /tmp/myapp.tar.gz

由於(希望)顯而易見的原因,這種呼叫方法是有問題的。

我真的希望我可以通過讀取標準輸入或其他形式的管道或緩衝區來讓這個 bash 腳本工作。有什麼想法可以讓它發揮作用嗎?

cat > file無論您何時呼叫它,只要您之前沒有從它讀取並“用完”輸入流,或者關閉文件描述符,它都應該工作,而您沒有這樣做。這是一個完全合法且正常的命令,並且至少在我這邊有效。

引用自:https://unix.stackexchange.com/questions/119019