抑制 echo 指令的執行追蹤?

抑制 echo 指令的執行追蹤?

我正在從 Jenkins 運行 shell 腳本,它使用 shebang options 啟動 shell 腳本#!/bin/sh -ex

根據Bash Shebang 適合傻瓜嗎?, -x, “使 shell 列印執行追蹤”,這對於大多數用途都非常有用 - 除了 echo:

echo "Message"

產生輸出

+ echo "Message"
Message

這有點多餘,而且看起來有點奇怪。有沒有辦法保持-x啟用狀態,但僅輸出

Message

而不是上面的兩行,例如透過在 echo 命令前添加特殊命令字元或重定向輸出?

答案1

當你被鱷魚逼到脖子的時候,很容易忘記我們的目標是排乾沼澤。                    ——流行說法

問題是關於echo,但到目前為止,大多數答案都集中在如何潛入命令set +x

{ echo "Message"; } 2> /dev/null

{ …; } 2> /dev/null (我承認,如果我沒有在先前的答案中看到它,我可能不會想到這一點。)

這有點麻煩,但是,如果您有一組連續的echo命令,則不需要單獨對每個命令執行此操作:

{
  echo "The quick brown fox"
  echo "jumps over the lazy dog."
} 2> /dev/null

請注意,當有換行符號時,不需要分號。

您可以使用以下方法減輕打字負擔克諾布的想法 永久開啟/dev/null非標準檔案描述符(例如,3),然後說2>&3而不是2> /dev/null一直打開。


在撰寫本文時,前四個答案需要做一些特殊的事情(並且在大多數情況下很麻煩) 每一個當你做一個echo.如果你真的想要全部 echo命令來抑制執行追蹤(為什麼不呢?),您可以在全域範圍內執行此操作,而無需修改大量程式碼。首先,我注意到沒有跟蹤別名:

$ myfunc()
> {
>     date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016  0:00:00 AM           # Happy Halloween!
$ myfunc
+ myfunc                                # Note that function call is traced.
+ date
Mon, Oct 31, 2016  0:00:01 AM
$ myalias
+ date                                  # Note that it doesn’t say  + myalias
Mon, Oct 31, 2016  0:00:02 AM

(請注意,如果 shebang 是#!/bin/sh,則以下腳本片段有效,即使/bin/sh是 bash 的連結。但是,如果 shebang 是#!/bin/bash,則需要添加一個shopt -s expand_aliases命令來獲取別名以在腳本中使用。)

所以,對於我的第一個技巧:

alias echo='{ set +x; } 2> /dev/null; builtin echo'

現在,當我們說 時echo "Message",我們正在呼叫別名,該別名不會被追蹤。別名關閉追蹤選項,同時抑制set命令中的追蹤訊息(使用中首先介紹的技術)用戶5071535的回答),然後執行實際的echo命令。這使我們能夠獲得與 user5071535 的答案類似的效果,而無需編輯程式碼每一個 echo命令。但是,這會使追蹤模式關閉。我們不能將 a 放入set -x別名中(或至少不容易),因為別名只允許用字串替換單字;別名字串的任何部分都不能注入到命令中 參數(例如,"Message")。因此,例如,如果腳本包含

date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date

輸出將是

+ date
Mon, Oct 31, 2016  0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016  0:00:04 AM           # Note that it doesn’t say  + date

因此,在顯示訊息後,您仍然需要重新開啟追蹤選項,但每次只需要一次堵塞連續echo命令數:

date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date


那就太好了如果我們能set -x在之後製造出自動裝置echo——我們可以,但需要更多的技巧。但在我介紹這一點之前,請先考慮一下這一點。 OP 從使用#!/bin/sh -exshebang 的腳本開始。使用者可以隱式地x從 shebang 中刪除 並擁有一個正常工作的腳本,而無需執行追蹤。如果我們能夠開發出保留該屬性的解決方案,那就太好了。這裡的前幾個答案未能滿足該屬性,因為它們無條件地「返回」追蹤echo語句,而不考慮它是否已經打開。  這個答案顯然沒有認識到這個問題,因為取代 echo帶有追蹤輸出的輸出;因此,如果關閉跟踪,所有訊息都會消失。我現在將提出一個解決方案,在echo聲明後重新打開跟踪有條件的- 僅當它已經打開時。將其降級為無條件「返回」追蹤的解決方案是微不足道的,可以作為練習。

alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
        builtin echo "$*"
        case "$save_flags" in
         (*x*)  set -x
        esac
}

$-是選項清單;與設定的所有選項相對應的字母串聯。例如,如果設定了e和選項,那麼將是包含和 的一堆字母。我的新別名(上面)保存了關閉追蹤之前的值。然後,在關閉追蹤的情況下,它將控制權交給 shell 函數。函數執行實際操作 ,然後檢查呼叫別名時是否開啟了該選項。如果該選項已打開,該函數會將其重新開啟;如果它關閉了,該功能就會將其關閉。x$-ex$-echox

shopt您可以在腳本開頭插入以上七行(如果包含 則為八行),而保留其餘部分。

這會讓你

  1. 使用以下任 shebang 行:
    #!/bin/sh -ex
    #!/bin/sh -e
    #!/bin/sh –x
    或者只是簡單的
    #!/bin/sh
    它應該按預期工作。
  2. 有這樣的程式碼
    (舍邦)
    命令1
    命令2
    命令3
    設定-x
    命令4
    命令5
    命令6
    設定+x
    命令7
    命令8
    命令9
    • 命令 4、5 和 6 將被追蹤 — 除非其中之一是echo,在這種情況下它將被執行但不被追蹤。 (但即使命令 5 是一個echo,命令 6 仍然會被追蹤。)
    • 命令 7、8 和 9 將不會被追蹤。即使命令 8 是echo,命令 9 仍然不會被追蹤。
    • 命令 1、2 和 3 將被追蹤(如 4、5 和 6)或不被追蹤(如 7、8 和 9),取決於 shebang 是否包含x.

PS我發現,在我的系統上,我可以省略builtin中間答案中的關鍵字(只是 的別名echo)。這並不奇怪; bash(1) 表示,在別名擴展期間,...

…。與正在擴展的別名相同的單字不會再次擴展。這意味著人們可以別名lsls -F例如,bash 不會嘗試遞歸地擴展替換文字。

毫不奇怪,如果省略關鍵字1echo_and_restore ,最後一個答案(有 的答案)就會失敗。但是,奇怪的是,如果我刪除並切換順序,它會起作用:builtinbuiltin

echo_and_restore() {
        echo "$*"
        case "$save_flags" in
         (*x*)  set -x
        esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'

__________
1 它似乎會引起未定義的行為。我見過

  • 無限循環(可能是因為無界遞歸),
  • 錯誤/dev/null: Bad address訊息,以及
  • 核心轉儲。

答案2

我在以下位置找到了部分解決方案資訊科技:

#!/bin/bash -ex
set +x; 
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"

輸出

set +x; 
shell tracing is disabled here 
+ echo "but is enabled here"
but is enabled here

不幸的是,那聲音仍然在迴響set +x,但至少在那之後很安靜。所以這至少是問題的部分解決方案。

但是否有更好的方法來做到這一點? :)

答案3

這種方法透過消除輸出來改進您自己的解決方案set +x

#!/bin/bash -ex
{ set +x; } 2>/dev/null
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"

答案4

放在set +x括號內,因此它僅適用於本地範圍。

例如:

#!/bin/bash -x
exec 3<> /dev/null
(echo foo1 $(set +x)) 2>&3
($(set +x) echo foo2) 2>&3
( set +x; echo foo3 ) 2>&3
true

會輸出:

$ ./foo.sh 
+ exec
foo1
foo2
foo3
+ true

相關內容