Переменная Bash не повторяется в перенаправлении вывода после curl или wget - PullRequest
1 голос
/ 14 апреля 2019

Я столкнулся со странным поведением переменной Bash при перенаправлении после curl команды:

curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"

Я создал следующий тестовый скрипт ./curl_test.sh:

#!/bin/env bash
i=0
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
echo "This is i: ${i}"
ls -1 ./out_curl_*.txt

j=0
echo 'hello' > "./out_echo_$((++j)).txt"
echo 'hello' > "./out_echo_$((++j)).txt"
echo "This is j: ${j}"
ls -1 ./out_echo_*.txt

exit 0

Выход:

$ ./curl_test.sh
This is i: 0
./out_curl_1.txt
This is j: 2
./out_echo_1.txt
./out_echo_2.txt

Ожидаемый результат:

$ ./curl_test.sh
This is i: 2
./out_curl_1.txt
./out_curl_2.txt
This is j: 2
./out_echo_1.txt
./out_echo_2.txt

Пожалуйста, кто-нибудь знает, почему это? Что уже опробовано:

wget имеет такое же поведение:

wget -q -O - 'https://www.google.com' > "./out_wget_$((++k)).txt"

Инкапсуляция curl в подоболочку ( ... ) не помогает.

Этот 2 лайнера, конечно, работает:

((i++))
curl -s 'https://www.google.com' > "./out_curl_${i}.txt"

Спасибо за любые подсказки.

1 Ответ

2 голосов
/ 14 апреля 2019

Обработка перенаправлений обычно выполняется после разветвления подпроцесса, но обязательно выполняется до с использованием execve() для передачи управления из оболочки в новый исполняемый файл (в вашем случаеcurl или wget) выполняется в этом процессе.

Поскольку вы уже fork() 'd, изменения в переменных происходят в контексте нового процесса и не передаются обратно вparent.

Это не относится к стандартному echo, поскольку он встроен в оболочку и, следовательно, находится в процессе (вообще не требует fork), но не делает применяется к /bin/echo для оболочек, реализованных таким образом (что стандарт POSIX не запрещает и не требует).


Более простой способ воспроизведения этой проблемы - показывает, что он применяется к all не встроенные команды - следует, как сгенерировано с помощью bash 3.2.57, а также воспроизведено для 4.4.23:

$ i=0; echo >>"test$((++i)).tmp"; echo "$i"
1
$ i=0; /bin/echo >>"test$((++i)).tmp"; echo "$i"
0

Если вы хотите обойти эту проблему, вы можете сделатьтак, выполнив перенаправлениеn для всей группы команд:

$ i=0; { /bin/echo; } >>"test$((++i)).tmp"; echo "$i"
1

Конструкция { ...; } выполняет перенаправление для всего блока команд и, таким образом, выполняет перенаправление до того, как разветвляется от дочернего процесса, который будетзаменено на /bin/echo.

...