我經常輸入 bash 命令,例如while true – 顯示 xyz 的狀態 – 睡眠 1 秒:
while true; do
echo "I am looking up some stuff and displaying the current result!"
sleep 1
done
然后我有時意識到使用Ctrl 再次打破回圈很困難c,因為它只會取消我的“有效負載”命令并繼續回圈,所以通常(在第一次運行之后)我輸入
while true; do
echo "I am looking up some stuff and displaying the current result!"
sleep 1
read -t 0.1 -N 1 input;
if [[ ! -z "$input" ]]; then
break;
fi;
done
但正如您所看到的,這基本上只需要一行代碼(echo本例中的代碼)就需要大量輸入。有什么方法可以使“執行命令和睡眠的可破壞回圈”可重用,例如作為函式?
我已經嘗試過eval:
function runinloop {
while true; do
eval -- "$@"
sleep 1
read -t 0.1 -N 1 input
if [[ ! -z "$input" ]]; then
break
fi
done
}
但是,當我運行更復雜的東西時
runinloop curl --silent "https://api.stackexchange.com/2.3/questions?tagged=caesar&site=stackoverflow" | gunzip | jq
...它吞下每個輸出并在我退出回圈后將其吐出。
uj5u.com熱心網友回復:
anything | gunzip
總是會“吞下每一個輸出”——它會壓縮。我想你想要:
anything 'curl ... "stuff&stuff" | gunzip'
請注意,這eval是邪惡的。&在您發布的代碼中,字符caesar&site=st被解釋為curl 在后臺運行。然后執行第二個命令 site=stackoverflow,將變數設定site為stackoverflow. 使用時請注意注意事項eval。你必須雙引號你的命令才能正確執行。
正因為如此,我推薦一個功能,它在安全性和可讀性方面都取得了勝利:
work() {
curl --silent \
"https://api.stackexchange.com/2.3/questions?tagged=caesar&site=stackoverflow" |
gunzip | jq
}
runinloop() {
...
"$@"
..
}
runinloop work
無論如何,使用watch:
work() {
...
}
export -f work
watch bash -c work
sleep 1 read -t 0.1 -N 1 input
只是read -t 1,它已經睡著了。
uj5u.com熱心網友回復:
只需在命令中添加單引號,它就可以正常作業。
改變
runinloop curl --silent "https://api.stackexchange.com/2.3/questions?tagged=caesar&site=stackoverflow" | gunzip | jq
到
runinloop 'curl --silent "https://api.stackexchange.com/2.3/questions?tagged=caesar&site=stackoverflow" | gunzip | jq'
你的腳本
#!/bin/bash
function runinloop {
while true; do
eval -- "$@"
sleep 1
read -t 0.1 -N 1 input
if [[ ! -z "$input" ]]; then
break
fi
done
}
runinloop 'curl --silent "https://api.stackexchange.com/2.3/questions?tagged=caesar&site=stackoverflow" | gunzip | jq'
有用:
bash test.sh
{
"items": [],
"has_more": false,
"quota_max": 300,
"quota_remaining": 206
}
{
"items": [],
"has_more": false,
"quota_max": 300,
"quota_remaining": 205
}
{
"items": [],
"has_more": false,
"quota_max": 300,
"quota_remaining": 204
}
{
"items": [],
"has_more": false,
"quota_max": 300,
"quota_remaining": 203
}
uj5u.com熱心網友回復:
然后我有時意識到使用 Ctrl C 很難再次打破回圈,因為它只會取消我的“有效負載”命令并繼續回圈
只有當您的“有效載荷”陷阱時才會發生這種情況SIGINT。
我能想到兩種可能的解決方案:
按 Ctrl C 兩次。第一個 Ctrl C 將中斷您的有效負載,第二個將中斷
sleep并跳出回圈(因為sleep不陷阱SIGINT,它將傳播到外殼)。如果您的“有效負載”在中斷時回傳非零狀態,則可以按如下方式修改回圈:
while payload; do sleep 1; done你甚至可以定義一個別名
alias nap="do sleep 1; done"并為自己節省更多的打字時間
while payload; nap
更新:
SIGINT這是一個捕獲并回傳非零退出狀態的程式的簡單示例:
#include <csignal>
#include <cstdlib>
#include <thread>
int main()
{
std::signal(SIGINT, [](int) { std::exit(1); });
std::this_thread::sleep_for(std::chrono::seconds{ 3 });
return 0;
}
uj5u.com熱心網友回復:
有什么方法可以使“執行命令和睡眠的可破壞回圈”可重用,例如作為函式?
它在某種程度上取決于您想要的語意,尤其是當命令失敗時(包括當它,而不是sleep,是接收 Ctrl-C 的行程時)。然而,無論如何,關鍵點是當一個行程被信號殺死時,它的退出狀態會傳達該資訊。特別是,當終端中的前臺行程通過按 Ctrl-C 被終止時,shell 回傳的退出狀態為 128 2 = 130。
您可以使用它來撰寫一個重復的函式,直到被信號終止:
repeat_until_signaled() {
local exit_status
while true; do
"$@" && sleep 1
exit_status=$?
if [[ $exit_status -gt 128 ]]; then
# The command or the sleep was interrupted by a signal
return $exit_status
fi
done
}
該特定實作還通過信號將指示終止的退出狀態轉發給函式的呼叫者。
您只需將函式名稱放在要重復的簡單命令前面即可使用它,如下所示:
repeat_until_signaled echo "Looking up stuff ..."
但是請注意,這僅適用于重復簡單命令,而不適用于復合命令、多命令串列或多命令管道。另一方面,復合命令等。可以通過將它們包裝在 shell 函式中來將它們變成簡單的命令。
另請注意,您指定的任何重定向都將應用于整個函式呼叫,而不僅僅是重復的命令。同樣,任何環境變數設定必須在函式名稱之前,并且將應用于整個函式呼叫,而不僅僅是重復的命令。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/432627.html
標籤:重击
