select и trap INT показывают другое поведение в случае подстановки команд в BASH

#bash #shell

Вопрос:

Обычно, когда INT оказывается в ловушке, select не дают shell немедленно отреагировать Ctr-C сигналом. Когда этот сценарий запускается , а затем нажимается пользователем Ctr-C , ничего не происходит. Пользователь должен нажать RETURN , что-то напечатать, а затем RETURN снова нажать, чтобы увидеть trap , что работает.

 trap 'echo INT signal TRAPPED; exit 0' INT

a=(A B C)

function choose_item ()
{
PS3="Choose an item in the preceding list: "
select n in ${a[*]}; do
  echo "You choose $n"
  return 0
done
}

choose_item
#$(choose_item)
 

Однако, когда мы:

  1. прокомментируйте строку choose_item
  2. раскомментируйте строку $(choose_item)
  3. запустите сценарий
  4. нажимает Ctr-C,

сценарий немедленно завершается и показывает, что ловушка работает. Так какова же роль command substitution ?

Ответ №1:

С $(choose_item) вами начнется другой процесс. Командная строка заменяется выводом этого процесса.

 my_echo() {
   echo "echo again"
}
my_echo
$(my_echo)
 

возвращает
эхо снова
и снова
Второй вызов вернул команду echo again . Вы можете увидеть нормальный вывод с echo "$(my_echo)" помощью .
Это системный вызов select , который не любит, когда его убивают, см. https://unix.stackexchange.com/q/513466/57293. С choose_item вами пошлите сигнал на select -вызов, и это будет отложено.
При использовании вы $(choose_item) запускаете не select подпроцесс , а подпроцесс, вызывающий вашу функцию. В этом случае вы убьете подпроцесс, который работает «без проблем».
Когда вам понравится поведение «убить без промедления $(choose_item) «, измените свою функцию:

 choose_item () {
   (
   PS3="Choose an item in the preceding list: "
   select n in ${a[*]}; do
     echo "You choose $n"
     return 0
   done
   )
}
 

Теперь select это вызывается в подпроцессе, и вы можете choose_item это сделать .