如何在程式輸出前添加字串而不等待整行?

如何在程式輸出前添加字串而不等待整行?

我有一個使用 SSH 在遠端伺服器上運行命令的腳本。我想將字串新增Remote:到輸出的每一行,但我不希望每行都延遲,直到整行可用。這是我的命令的輸出:

$ myproject-db-push my_database_name
正在從資料庫匯出...完成
歸檔資料...完成
正在將存檔上傳到遠端...完成
在遠端運行安裝腳本
遠端:將存檔解壓縮到臨時目錄...完成
遠端:使用資料庫:my_database_name
遠端:刪除集合:
遠端:- my_collection_foo
遠端: - my_collection_bar
遠端:導入新資料...完成

在這種情況下,我使用sed這樣的:

echo "$INSTALLCMD" | ssh -T "deploy@$SERVER" | sed -u "s/^/Remote: /"

問題是,正如我所解釋的,沒有部分的行被印到螢幕上。如果我刪除該| sed部件,它就會按預期工作。首先這樣寫:

正在導入新資料...

幾秒鐘後,該行完成:

導入新資料...完成

我假設sed只能逐行工作。我嘗試將其設為無緩衝,但它仍然等待整行。有其他方法可以實現此目的嗎?

答案1

這有點棘手,因為所有這些實用程式(sedawkgrep)都是行緩衝的。這意味著它們僅在該行完成(出現換行符)時才列印輸出。他們無法逐字符讀取輸入。

因此,為了進行測試,我製作了一個小序列,模擬您的行為:

{ 
  echo -n "first task: "
  sleep 2
  echo "done"
  echo -n "second task: "
  sleep 2
  echo "done"
}

正如您的問題一樣,它會first task:在 2 秒後列印done。將其複製到終端中,親自嘗試。

解決方案:

在命令後面添加以下內容:

IFS=
command | { x=1; while IFS= read -d'' -s -N 1 char; do
  [ $x ] && printf "Remote: "
  printf "$char"
  unset x
  [ "$char" == "
" ] && x=1
done; }

解釋:

內建readbash可以逐字讀取輸入。此部分read -d'' -s -N 1 char停用分隔符-d'',啟動靜默模式-s,並且一次僅將 1 個字元讀-N 1入變數$char。然後該命令檢查變數是否$x存在。如果是,我們換行並列印“前綴”。然後列印字元。取消設定$x。然後最後一條語句檢查該字元是否為換行符。如果它是設定$x為和 的換行符1,則在下一個循環中,將列印「前綴」。

當您連接兩個序列時,可以測試整個事情:

{ 
  echo -n "first task: "
  sleep 2
  echo "done"
  echo -n "second task: "
  sleep 2
  echo "done"
} | { x=1; while IFS= read -d'' -s -N 1 char; do
  [ $x ] && printf "Remote: "
  printf "$char"
  unset x
  [ "$char" == "
" ] && x=1
done; }

相關內容