Как я заменяю переменную фоновой функции?

Я работал над сценарием для своего родительского элемента, который управляет несколькими задачами через сценарий со многими функциями что цепочка вместе (организационные цели). Этот сценарий полагается полностью на zenity для всего взаимодействия с пользователем (мой родительский элемент является действительно техническим неграмотным {Возраст 60 +}).

Проблема, которую я имею, является этим, после того как я вызываю функцию transprog это не выйдет из цикла даже после переменной что while цикл полагается, изменяется за пределами функции.

Цикл называют здесь:

copystat="1"
transprog & cp -rf "$netlocdirFIN/" "$transdir2/" # "transprog" is called here
copystat="0"
sleep 1
ret="$?"
echo "$ret"
transnew #calls next step/function

И это transprog функция:

transprog ()
{
i2="Im Working On It!"

(
while [ $copystat = 1 ]; do
# =================================================================
echo "25"
echo "# ^_^ $i2" ; sleep 1

# =================================================================
echo "50"
echo "# ^-^ $i2" ; sleep 1

# =================================================================
echo "75"
echo "# ^_^ $i2" ; sleep 1


# =================================================================
echo "99"
echo "# ^-^ $i2" ; sleep 1

done
echo "# Your files are DONE TRANSFERING!" ; sleep 1
echo "100"
) |
zenity --progress \
  --title="File Transfer In Progress" \
  --text="# Im Getting Warmed Up" \
  --percentage=0 \
  --auto-close \
  --auto-kill
}

После того как копия сделана, сценарий продвигается: zenity индикатор выполнения в фоновом режиме тикает, и он действительно смущает его.

Как я могу сказать фоновой функции выходить?

(zenity использует echo значения 25,50,75 и 99 для изменения "полноты" индикатора выполнения. и echo "# (whatever)" изменить текст.)

все, что это, является чем-то, чтобы сказать ему "Эй Duffus, я - bussy, копирование материала не отключает меня"

я попробовал решение Guss: (разделенный сценарий в тестовых целях)

#!/bin/bash

transtest ()
{

i2="Im Working On It!"

var=0
trap 'var=1' 2

(
while [ "$var" = 0 ]; do
# =================================================================
echo "25"
echo "# ^_^ $i2" ; sleep 1

# =================================================================
echo "50"
echo "# ^-^ $i2" ; sleep 1

# =================================================================
echo "75"
echo "# ^_^ $i2" ; sleep 1

# =================================================================
echo "99"
echo "# ^-^ $i2" ; sleep 1


done
echo "# Your files are DONE TRANSFERING!" ; sleep 1
echo "100"
) |
zenity --progress \
  --title="File Transfer In Progress" \
  --text="# Im Getting Warmed Up" \
  --percentage=0 \
  --auto-close \
  --auto-kill
}

transtest &
pid=$!
echo "$pid"
sleep 20 #code to copy? or just for this test?
echo "Killing Child: $pid"
kill -2 "$pid"
echo "wait"
wait
exit

я вижу результат echo "wait" и это все еще сохраняет цикличное выполнение.

0
задан 4 February 2016 в 12:46

2 ответа

Вы изменили значение условной переменной (copystat) внешняя сторона while цикл (работающий в подоболочке), который выходит за рамки while цикл. Если у Вас не будет некоторого условия в самом цикле, чтобы инициировать условие выхода цикла или использовать IPC, цикл продолжится навсегда.

, Таким образом, решение состоит в том, чтобы включить копирование или любую другую условную логику в while сам цикл для инициирования выхода, Или можно думать об изменении дизайна в целом делать это более устойчивым в таких ситуациях Или использовать IPC , упомянутый здесь .

1
ответ дан 26 July 2019 в 08:19

Проблема, которую Вы имеете, вызывается подоболочкой, порожденной, когда Вы звоните transprog для выполнения в фоновом режиме (что & символ делает). Необходимо понять, что сценарий удара не является программой, а сценарием оболочки, который ведет себя согласно правилам оболочки - оболочка может только выполнить один процесс за один раз и ожидать его для завершения.

" система заданий " позволяет Вам выполнять другой процесс и не ожидать его, но когда тот процесс будет функцией, определяемой в ударе, удар будет метать икру "sub оболочка" что" копии " все переменные и функции исходной оболочки и дорожка что как задание. Скопированная оболочка не знает об изменениях, внесенных это ее родительская оболочка - потому что это не ссылается на родительские переменные оболочки непосредственно - просто копия их.

то, Что необходимо сделать для фонового цикла, должно использовать Механизм связи Процесса Интера ( IPC), чтобы позволить родительской оболочке уведомить цикл в подоболочке для прерывания. Для такой простой передачи сигналов обычно "Сигнал POSIX" является соответствующим.

самый соответствующий сигнал использовать является "сигналом прерывания", SIGINT (сигнал номер 2), который является тем, что производится, когда Вы нажимаете CTRL+C, и это обычно останавливает Ваш сценарий. Но мы можем поймать этот сигнал и обновить локальный вариант с помощью trap встроенная команда.

Вот простой пример:

#!/bin/bash

function test() {
  var=0
  trap 'var=1' 2
  while [ "$var" = 0 ]; do
    sleep 3
    echo 'still sleeping'
  done
  echo "done sleeping"
}

test &
pid=$!
echo $pid;
sleep 5
echo "Killing $pid"
kill -2 "$pid"
wait

Это произведет:

$ ./test.sh 
8359
still sleeping
Killing 8359
still sleeping
done sleeping

, Что происходит, вот то, что после 5 секунд там цикл завершил один раунд и теперь спит на втором раунде, когда родитель использует kill встроенный для передачи сигналов о подоболочке. Сон подоболочки прерван, он получает сигнал и обновляет переменную, затем возобновляет сон, Когда цикл просыпается, он производит текст, затем возвращается и видит, что var изменил и оставляет цикл.

я использую wait встроенный в родителе только, чтобы удостовериться, что родительский процесс не выходит перед подоболочкой. Это по существу "ожидает" подоболочки для окончания.

[ОБНОВЛЕНИЕ] После рассмотрения OP немного больше, существует еще несколько продолжений подоболочек, и я не хочу бороться с этим - подоболочки (в дополнение к функциям) являются хорошим способом управлять сложностью в сценарии - но это действительно делает нахождение, что корректный PID отправляет сигнал в бит трудный.

Вместо этого мы можем использовать другой механизм IPC, названный "сегментом общей памяти". Это позволяет процессу выделять пакет памяти, присваивать ей имя и позволять нескольким процессам получить доступ к той же памяти (она охвачена в документе IPC, связанном выше, более подробно). В то время как в Bash мы не можем непосредственно обратиться к той функции (в отличие от того, что программа C, например, может сделать), мы можем использовать механизм Linux, который выставляет общую память IPC любой программе через /dev/shm категория устройств. Таким образом, сценарий OP мог бы выглядеть примерно так:

#!/bin/bash

transtest () {
  local sync="$1"
  i2="Im Working On It!"
  var=0
  (
    while [ -z "$(cat $sync)" ]; do sleep 1; done
    echo "# Your files are DONE TRANSFERING!"
    sleep 1
    echo "100"
  ) | zenity --progress --title="File Transfer In Progress" --text="# Im Getting Warmed Up" \
    --percentage=0 --pulsate --auto-close --auto-kill
}

sync=/dev/shm/syntest-$ # allocate a shared memory segment name for this process
echo '' > $sync # init the shm
transtest $sync &
sleep 20
echo "Signaling done"
echo "done" > $sync
echo "waiting"
wait
# remove the shm segment. While not actually necessary (it will clear
# when you reboot), I like to keep a clean system
rm $sync 
exit

В основном, мы рассматриваем сегмент SHM как файл и просто храним некоторые данные там. Цикл продолжает читать "файл" и когда существует содержание там, это вспыхивает.

Один вопрос остается, почему не только выделяют временный файл (использующий mktemp) и использование это для синхронизации? Хорошо - который работал бы почти то же! Основное различие, и почему я предпочитаю ОТМЕТКУ КУРСА КОРАБЛЯ для такой вещи, то, что не действительно файл и не подвергается файловая система операции IO, ошибки диска и подобные, и если я не очищу его, то это закончится в следующий раз начальные загрузки системы.

2
ответ дан 26 July 2019 в 08:19

Другие вопросы по тегам:

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