Один очень надежный способ справиться с сопроцессами в Bash состоит в том, чтобы использовать ... coproc
встроенный.
Предположим, у вас есть сценарий или функция с именем banana
, которые вы хотите запустить в фоновом режиме, захватить все свои результаты, выполняя некоторые stuff
и ждать, пока это не будет сделано. Я сделаю симуляцию с этим:
banana() {
for i in {1..4}; do
echo "gorilla eats banana $i"
sleep 1
done
echo "gorilla says thank you for the delicious bananas"
}
stuff() {
echo "I'm doing this stuff"
sleep 1
echo "I'm doing that stuff"
sleep 1
echo "I'm done doing my stuff."
}
Затем вы запустите banana
с помощью coproc
так:
coproc bananafd { banana; }
это похоже на запуск banana &
, но со следующими дополнительными функциями: он создает два дескриптора файла, которые находятся в массиве bananafd
(по индексу 0
для вывода и индекс 1
для ввода). Вы будете записывать вывод banana
с помощью read
builtin:
IFS= read -r -d '' -u "${bananafd[0]}" banana_output
Попробуйте:
#!/bin/bash
banana() {
for i in {1..4}; do
echo "gorilla eats banana $i"
sleep 1
done
echo "gorilla says thank you for the delicious bananas"
}
stuff() {
echo "I'm doing this stuff"
sleep 1
echo "I'm doing that stuff"
sleep 1
echo "I'm done doing my stuff."
}
coproc bananafd { banana; }
stuff
IFS= read -r -d '' -u "${bananafd[0]}" banana_output
echo "$banana_output"
Предостережение: вы должны выполнить stuff
до banana
заканчивается! если горилла быстрее вас:
#!/bin/bash
banana() {
for i in {1..4}; do
echo "gorilla eats banana $i"
done
echo "gorilla says thank you for the delicious bananas"
}
stuff() {
echo "I'm doing this stuff"
sleep 1
echo "I'm doing that stuff"
sleep 1
echo "I'm done doing my stuff."
}
coproc bananafd { banana; }
stuff
IFS= read -r -d '' -u "${bananafd[0]}" banana_output
echo "$banana_output"
В этом случае вы получите ошибку, подобную этой:
./banana: line 22: read: : invalid file descriptor specification
Вы можете проверить, слишком ли поздно ( т.е. если вы слишком долго выполняете свой stuff
), потому что после выполнения coproc
bash удаляет значения в массиве bananafd
, и поэтому мы получили предыдущую ошибку.
#!/bin/bash
banana() {
for i in {1..4}; do
echo "gorilla eats banana $i"
done
echo "gorilla says thank you for the delicious bananas"
}
stuff() {
echo "I'm doing this stuff"
sleep 1
echo "I'm doing that stuff"
sleep 1
echo "I'm done doing my stuff."
}
coproc bananafd { banana; }
stuff
if [[ -n ${bananafd[@]} ]]; then
IFS= read -r -d '' -u "${bananafd[0]}" banana_output
echo "$banana_output"
else
echo "oh no, I took too long doing my stuff..."
fi
Наконец, если вы действительно не хотите пропустить какие-либо движения горилл, даже если вы слишком долго заработаете для своего stuff
, вы можете скопировать дескриптор файла banana
в другой fd, 3
для например, сделайте свой материал, а затем прочитайте из 3
:
#!/bin/bash
banana() {
for i in {1..4}; do
echo "gorilla eats banana $i"
sleep 1
done
echo "gorilla says thank you for the delicious bananas"
}
stuff() {
echo "I'm doing this stuff"
sleep 1
echo "I'm doing that stuff"
sleep 1
echo "I'm done doing my stuff."
}
coproc bananafd { banana; }
# Copy file descriptor banana[0] to 3
exec 3>&${bananafd[0]}
stuff
IFS= read -d '' -u 3 output
echo "$output"
Это будет работать очень хорошо! последний read
также будет играть роль wait
, так что output
будет содержать полный вывод banana
.
Это было замечательно: никаких временных файлов для обработки (баш-ручки все тихо) и 100% чистый баш!
Надеюсь, что это поможет!
Это точно так же, разницы нет вообще. Стандартным оператором фактически является not in
(см. документы ), форма not 7 in
автоматически преобразуется в 7 not in
.
Таким образом, рекомендуемый способ - if 7 not in [5, 6, 7]
, это прямое использование оператора, а также улучшенная читаемость.
Они абсолютно одинаковы и, следовательно, занимают одинаковое количество времени. not in
это просто синтаксический сахар. Используя модуль dis
, мы можем видеть, что оба результата приводят к одному и тому же байт-коду:
>>> dis.dis("not x in y")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 7 (not in)
6 RETURN_VALUE
>>> dis.dis("x not in y")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 7 (not in)
6 RETURN_VALUE
Даже добавление скобок в качестве not (x in y)
не меняет этого, если, конечно, вы не добавите больше в скобки :
>>> dis.dis("not (x in y)")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 7 (not in)
6 RETURN_VALUE
>>> dis.dis("not (x in y or z)")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 6 (in)
6 JUMP_IF_TRUE_OR_POP 10
8 LOAD_NAME 2 (z)
>> 10 UNARY_NOT
12 RETURN_VALUE
Протестировано с Python 3.6.7 и 2.7.15.