Bash

當“選擇”循環執行時,Bash 忽略 SIGINT 陷阱

  • April 10, 2020

當我將“陷阱”與選擇循環結合使用時,即當我嘗試在顯示選項時按 CTRL+C 來突破時,它只會在終端中列印 ^C。如果我從腳本中刪除“陷阱”,它通常會退出,也就是說它會接受 CTRL+C。

我已經在兩種不同版本的 bash 上對此進行了測試(一種隨 CentOS 提供,另一種隨 Fedora 提供),我對 Fedora(4.4.23(1)-release)中的一個有問題。CentOS 附帶的 Bash 版本 4.2.46(2)-release 似乎工作正常。我還在本地終端和遠端(通過 ssh)上對此進行了測試。問題總是在 Fedora 方面。

我將發布程式碼以查看我在說什麼

這個不行:

#!/bin/bash

trap exit SIGINT

select opt in One Two Three; do
       break
done

如果我要刪除整個 ’trap exit SIGINT’ 行,它將正常工作並接受 CTRL+C 沒有問題。

任何想法如何解決或繞過這個?

任何想法如何解決或繞過這個?

您可以通過打開posix模式來繞過它,或者使用 --posix選項,或者暫時使用set -o posix

set -o posix
select opt in foo bar baz; do
   echo "opt=$opt"
done
set +o posix

有關此行為的解釋,您可以查看內置zread()函式使用的函式read(也由 bash in 內部呼叫select):

 while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
   /* XXX - bash-5.0 */
   /* We check executing_builtin and run traps here for backwards compatibility */
   if (executing_builtin)
     check_signals_and_traps ();   /* XXX - should it be check_signals()? */
   else
     check_signals ();

由於某些特殊原因,executing_builtin僅在read顯式呼叫內置函式時設置,而不是在由 呼叫時設置select。這看起來很像一個錯誤,而不是故意的。

在posix模式下執行時,信號將取消read內置。在這種情況下,zreadintr()被呼叫,與 不同的是,在執行陷阱後zread()不會重新呼叫中斷的系統呼叫。read(2)builtins/read.def

     if (unbuffered_read == 2)
       retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr);
     else if (unbuffered_read)
       retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1);
     else
       retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c);

read有關 bash內置的“重新啟動”的更多詳細資訊,請點擊此處

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