Почему устанавливает-e не, работают в подоболочках с круглой скобкой () сопровождаемый ИЛИ список ||?

Если модем распознан, но не удается соединиться, проверяют их (rfkill управляйте беспроводными устройствами, блокирующимися в Вашей системе):

# get a list of devices and states
rfkill list

# unblock all wireless devices. With one integrated card this is not enough
# for some reason and I have to leave it "on" on Windows 7 to 
# get it to work on linux

rfkill unblock all

Для фиксации мобильной широкополосной связи с 12d1:14d1 идентификатор следуют этим инструкциям (не протестированный). Попытайтесь создать этот файл к /etc/usb_modeswitch.d/12d1:14d1

########################################################
# Vodafone/Huawei K3770

DefaultVendor= 0x12d1
DefaultProduct=0x14d1

TargetVendor=  0x12d1
TargetProduct= 0x14c9

MessageContent="55534243123456780000000000000011062000000100000000000000000000"

CheckSuccess=20

или с этим содержанием

################################################## ######
# Huawei K3770

DefaultVendor= 0x12d1
DefaultProduct=0x14d1

TargetVendor= 0x12d1
TargetProduct= 0x1c05
CheckSuccess=20
MessageContent="55534243123456780000000000000011060000000000000000 000000000000"

После того теста это с

sudo usb_modeswitch -v 0x12d1 -p 0x14d1 -c /etc/usb_modeswitch.d/12d1:14d1

И если это работало, добавляют к /lib/udev/rules.d/40-usb_modeswitch.rules эти строки

# Huawei Ek3770
ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="14d1", RUN+="usb_modeswitch '%b/%k'

И я думаю, что Вам нужна версия usb-modeswitch по крайней мере 1.1.8, у меня нет Вашего точного 3g-модема и если я не ошибаюсь, эта палка должна быть добавлена к modeswitch базам данных в какой-то момент. Вы могли бы заставить это работать с версией дьявола.

usb-modeswitch - переключает режим USB-устройств "со многими состояниями"

** Создание инструкций, примерил человечность, ясную **

@see http://www.draisberghof.de/usb_modeswitch/#download

как корень работает, что-то вроде этого (не выполняйте это, если Вы не понимаете то, что он делает):

# remove usb-modeswitch installed from repos
dpkg -r usb-modeswitch
dpkg -r usb-modeswitch-data

cd /tmp
mkdir /tmp/compiledir
cd /tmp/compiledir
# get newest modeswitch at the time of this answer
wget http://www.draisberghof.de/usb_modeswitch/usb-modeswitch-1.2.2.tar.bz2
wget http://www.draisberghof.de/usb_modeswitch/usb-modeswitch-data-20120120.tar.bz2

# get required -dev files for compiling usb-modeswitch
apt-get build-dep usb-modeswitch

# install them
tar -jxf usb-modeswitch-1.2.2.tar.bz2 
cd usb-modeswitch-1.2.2
make install 
cd ..

tar -jxf usb-modeswitch-data-20120120.tar.bz2 
cd usb-modeswitch-data-20120120
make install 
cd ..

30
01.02.2018, 01:17
5 ответов

Согласно этому потоку, это - поведение, которое POSIX указывает для использования"set -e"в подоболочке.

(Я был удивлен также.)

Во-первых, поведение:

-e установка должна быть проигнорирована при выполнении составного списка после в то время как, пока, если, или elif зарезервированное слово, конвейер, начинающийся! зарезервированное слово или любая команда И - ИЛИ список кроме последнего.

Вторые примечания к сообщению,

Таким образом, не должен устанавливать-e в (код подоболочки) работают независимо от окружающего контекста?

Нет. Описание POSIX является четким, на который влияет окружающий контекст, проигнорирован ли установленный-e в подоболочке.

Существует немного больше в четвертом сообщении, также Eric Blake,

Точка 3 не требует, чтобы подоболочки переопределили контексты где set -e проигнорирован. Таким образом, после того как Вы находитесь в контексте где -e проигнорирован, нет ничего, что можно сделать для получения -e повиновавшийся снова, даже подоболочка.

$ bash -c 'set -e; if (set -e; false; echo hi); then :; fi; echo $?' 
hi 
0 

Даже при том, что мы звонили set -e дважды (и в родителе и в подоболочке), то, что подоболочка существует в контексте где -e проигнорирован (условие, если оператор), нет ничего, что мы можем сделать в подоболочке, чтобы повторно включить -e.

Это поведение определенно удивительно. Это парадоксально: можно было бы ожидать перевключение set -e иметь эффект, и что окружающий контекст не взял бы прецедент; далее, формулировка стандарта POSIX не делает это особенно ясным. При чтении его в контексте, где команда перестала работать, правило не применяется: это только применяется в окружающем контексте, однако, это относится к нему полностью.

33
27.01.2020, 19:38
  • 1
    Спасибо за те ссылки они были очень интересны. Однако мой пример (IMO), по существу отличающийся. Большая часть того обсуждения состоит в том, наследован ли установленный-e в родительской оболочке подоболочкой: set -e; (false; echo passed;) || echo failed. Меня, на самом деле, не удивляет, что-e проигнорирован в этом случае, учитывая формулировку стандарта. В моем случае, тем не менее, я явно устанавливаю-e в подоболочке и ожидаю, что подоболочка выйдет при отказе. Существует не И - ИЛИ список в подоболочке... –  MadScientist 21.02.2013, 14:36
  • 2
    я не соглашаюсь. Второе сообщение (я не могу добраться, привязки для работы) говорит, что "Описание POSIX является четким, на который влияет окружающий контекст, проигнорирован ли установленный-e в подоболочке". - подоболочка находится в И - ИЛИ список. –  Aaron D. Marasco 22.02.2013, 01:38
  • 3
    В четвертом сообщении (также Erik Blake) также говорится "Даже при том, что мы назвали набор-e дважды (и в родителе и в подоболочке), то, что подоболочка существует в контексте, где-e проигнорирован (условие, если оператор), нет ничего, что мы можем сделать в подоболочке, чтобы повторно включить-e". –  Aaron D. Marasco 22.02.2013, 01:41
  • 4
    Вы правы; я не уверен, как я неправильно читал их.Спасибо. –  MadScientist 22.02.2013, 07:00
  • 5
    я рад узнать, что это поведение я отрываю волосы, оказывается в спецификации POSIX. Таким образом, какова работа вокруг?! if и || и && заразны? это абсурдно –  Steven Lu 04.06.2015, 23:40

Я не исключил бы, это - ошибка просто, потому что несколько оболочек ведут себя тот путь.;-)

Я развлекаюсь еще больше для предложения:

start cmd:> ( eval 'set -e'; false; echo passed; ) || echo failed
passed

start cmd:> ( eval 'set -e; false'; echo passed; ) || echo failed
failed

start cmd:> ( eval 'set -e; false; echo passed;' ) || echo failed
failed

Позвольте мне заключить в кавычки из удара человека (4.2.24):

Оболочка не выходит, если команда, которая сбои являются [...] частью любой команды, выполняемой в && или || список кроме команды после финала && или || [...]

Возможно, оценка по нескольким командам приводит к игнорированию || контекст.

2
27.01.2020, 19:38
  • 1
    Ну, если все оболочки ведут себя тот способ, которым это - по определению не ошибка... это - стандартное поведение :-). Мы можем оплакивать поведение как неинтуитивное, но... Прием с оценкой очень интересен, это наверняка. –  MadScientist 21.02.2013, 14:42
  • 2
    чередования, Какую оболочку Вы используете? eval прием не работает на меня. Я попробовал удар, избейте posix режим и тире. –  Dunatotatos 12.09.2017, 19:40
  • 3
    @Dunatotatos, как Hauke заявил, который был bash4.2. Это было "зафиксировано" в bash4.3. находящиеся в pdksh оболочки будут иметь ту же "проблему". И несколько версий нескольких оболочек имеют все виды различных "проблем" с set -e. set -e повреждается дизайном. Я не использовал бы его ни для чего кроме самого простого из сценариев оболочки без управляющих структур, подоболочек или замен команды. –  Stéphane Chazelas 22.09.2017, 17:04

Действительно, set -e не действует внутри подоболочки, если вы используете после них оператор || ; например, это не сработает:

#!/bin/sh

# prints:
#
# --> outer
# --> inner
# ./so_1.sh: line 16: some_failed_command: command not found
# <-- inner
# <-- outer

set -e

outer() {
  echo '--> outer'
  (inner) || {
    exit_code=$?
    echo '--> cleanup'
    return $exit_code
  }
  echo '<-- outer'
}

inner() {
  set -e
  echo '--> inner'
  some_failed_command
  echo '<-- inner'
}

outer

Аарон Д. Мараско в своем ответе отлично объясняет, почему он так себя ведет.

Вот небольшой трюк, который можно использовать, чтобы исправить это: запустите внутреннюю команду в фоновом режиме и сразу же дождитесь ее. Встроенная функция wait вернет код выхода внутренней команды, и теперь вы используете || после wait , а не внутреннюю функцию, поэтому set -e правильно работает внутри последнего:

#!/bin/sh

# prints:
#
# --> outer
# --> inner
# ./so_2.sh: line 27: some_failed_command: command not found
# --> cleanup

set -e

outer() {
  echo '--> outer'
  inner &
  wait $! || {
    exit_code=$?
    echo '--> cleanup'
    return $exit_code
  }
  echo '<-- outer'
}

inner() {
  set -e
  echo '--> inner'
  some_failed_command
  echo '<-- inner'
}

outer

Вот общая функция, которая основывается на этой идее. Он должен работать во всех POSIX-совместимых оболочках, если вы удалите local ключевых слов, т.е. замените все local x = y только на x = y :

# [CLEANUP=cleanup_cmd] run cmd [args...]
#
# `cmd` and `args...` A command to run and its arguments.
#
# `cleanup_cmd` A command that is called after cmd has exited,
# and gets passed the same arguments as cmd. Additionally, the
# following environment variables are available to that command:
#
# - `RUN_CMD` contains the `cmd` that was passed to `run`;
# - `RUN_EXIT_CODE` contains the exit code of the command.
#
# If `cleanup_cmd` is set, `run` will return the exit code of that
# command. Otherwise, it will return the exit code of `cmd`.
#
run() {
  local cmd="$1"; shift
  local exit_code=0

  local e_was_set=1; if ! is_shell_attribute_set e; then
    set -e
    e_was_set=0
  fi

  "$cmd" "$@" &

  wait $! || {
    exit_code=$?
  }

  if [ "$e_was_set" = 0 ] && is_shell_attribute_set e; then
    set +e
  fi

  if [ -n "$CLEANUP" ]; then
    RUN_CMD="$cmd" RUN_EXIT_CODE="$exit_code" "$CLEANUP" "$@"
    return $?
  fi

  return $exit_code
}


is_shell_attribute_set() { # attribute, like "x"
  case "$-" in
    *"$1"*) return 0 ;;
    *)    return 1 ;;
  esac
}

Пример использования:

#!/bin/sh
set -e

# Source the file with the definition of `run` (previous code snippet).
# Alternatively, you may paste that code directly here and comment the next line.
. ./utils.sh


main() {
  echo "--> main: $@"
  CLEANUP=cleanup run inner "$@"
  echo "<-- main"
}


inner() {
  echo "--> inner: $@"
  sleep 0.5; if [ "$1" = 'fail' ]; then
    oh_my_god_look_at_this
  fi
  echo "<-- inner"
}


cleanup() {
  echo "--> cleanup: $@"
  echo "    RUN_CMD = '$RUN_CMD'"
  echo "    RUN_EXIT_CODE = $RUN_EXIT_CODE"
  sleep 0.3
  echo '<-- cleanup'
  return $RUN_EXIT_CODE
}

main "$@"

Выполнение примера:

$ ./so_3 fail; echo "exit code: $?"

--> main: fail
--> inner: fail
./so_3: line 15: oh_my_god_look_at_this: command not found
--> cleanup: fail
    RUN_CMD = 'inner'
    RUN_EXIT_CODE = 127
<-- cleanup
exit code: 127

$ ./so_3 pass; echo "exit code: $?"

--> main: pass
--> inner: pass
<-- inner
--> cleanup: pass
    RUN_CMD = 'inner'
    RUN_EXIT_CODE = 0
<-- cleanup
<-- main
exit code: 0

Единственное, что вам нужно знать при использовании этого метода, это то, что все изменения переменных Shell, выполненные с помощью команды, которую вы передаете в run , не будут распространяются на вызывающую функцию, поскольку команда выполняется в подоболочке.

7
27.01.2020, 19:38

Обходной путь при использовании верхнего уровняset -e

Я пришел к этому вопросу, потому что использовал set -eв качестве метода обнаружения ошибок:

/usr/bin/env bash
set -e
do_stuff
( take_best_sub_action_1; take_best_sub_action_2 ) || do_worse_fallback
do_more_stuff

и без ||скрипт перестанет работать и никогда не достигнет do_more_stuff.

Поскольку чистого решения, похоже, не существует, я думаю, что просто сделаю set +eпростое решение для своих скриптов:

/usr/bin/env bash
set -e
do_stuff
set +e
( take_best_sub_action_1; take_best_sub_action_2 )
exit_status=$?
set -e
if [ "$exit_status" -ne 0 ]; then
  do_worse_fallback
fi
do_more_stuff
2
20.08.2021, 13:15

Подход с запуском команды в фоновом режиме , предложенный @skozin , не будет работать в bash. bashпо-прежнему отключает set -eдля фоновых команд. Однако dashи ashработают нормально.

0
20.08.2021, 13:15

Теги

Похожие вопросы