Это не работает на многих уровнях. В основном, bash не очень хорош для многопоточного программирования. Но если вы собираетесь сделать это таким образом, вы должны осознать две вещи: (1) для того, чтобы ваш «поток» чтения ключей работал, он должен иметь монопольный доступ к tty. (2) Когда вы помещаете процесс в фоновый режим, он естественным образом копирует stdin из tty текущего процесса. (3) Обычно оболочка обнаруживает это и останавливает фоновый процесс.
Только процессы переднего плана могут читать из или, если пользователь так указывает с помощью stty tostop, записывать в терминал. Фоновые процессы, которые пытаются читать (записывать, когда действует stty tostop) терминала, посылают сигнал SIGTTIN (SIGTTOU) драйвером терминала ядра, который, если он не пойман, приостанавливает процесс.
Вы можете увидеть это здесь:
otheus@otheus-VirtualBox ~ $ ( while true; read x; do echo $x; done; ) &
[1] 2841
otheus@otheus-VirtualBox ~ $
[1]+ Stopped ( while true; read x; do
echo $x;
done )
Итак, процесс чтения tty должен быть на переднем плане. Фон может выполнять «работу», но сначала убедитесь, что вы закрыли stdin: <& -
Чтобы остановить «рабочий» процесс, вам нужно знать его pid. Для этого вам нужно включить управление заданиями в скрипте (по умолчанию оно отключено). set -m
делает это. Запустите его и убейте % -
после нажатия клавиши. Вы можете убедиться, что цикл нажатия клавиш завершается, когда это делает рабочий. Вы выполняете свой поток ключевого монитора:
start_worker &
while jobs %- &>/dev/null; do
read -n 1 -s -t 1 key
# test key
if [[ $key == q ]]; then
kill -1 %-
break
fi
fi
wait
Условие while проверяет, выполняется ли / распознано ли задание. После его завершения задания вернут false, и цикл завершится. Команда чтения теперь дополнительно истекает через 1 секунду. Наконец, после выхода из цикла подождите, чтобы убедиться, что задание «очищено».(Если у вас есть другие выполняемые задания, это будет зависеть здесь.)
Другое дело: то, что вы пытаетесь выполнить, по своей сути опасно. Смешивание корневого доступа и сценариев bash опасно . Здесь есть несколько тем, которые следует затронуть, например, что происходит, когда пользователь нажимает Control-C или Ctl-Z.
Наконец, я даже не уверен, что вы можете смешивать рабочий поток с su
, как в вашем примере. Когда su запускается, он изменяет текущий tty на root, не позволяя вашему рабочему потоку выводить на него данные.
Последнее не работает, потому что -exec
не зависит от -printf
.
Но вы можете использовать xargs
вместо-exec
:
find. -type f -printf '%P\n' \
| xargs -I{} aria2c -x 16 -s 1 "https://web.archive.org/save/https://{}"
Вы также можете позволить нескольким экземплярам aria2c
работать параллельно с xargs -P <num>
.
Еще лучше было бы создать файловый дескриптор из find
в качестве входных данных для aria2
вместо использования конвейеров и xargs
.
aria2c -x 16 -s 1 -i <(find. -type f -printf 'https://web.archive.org/save/https://%P\n')
Добавление -printf
приведет только к выводу, но не изменит то, чем заменяется {}
.
Кажется, curl
немного умнее (или, наоборот, применяет больше магии ), чем aria2
, и удаляет ./
. Начальное значение ./
в найденном пути исходит из того факта, что find
будет создавать пути относительно каталога верхнего уровня, с которого вы начинаете поиск.
Для вызова aria2
или curl
с URL-адресом, который не содержит начального ./
, используйте
find. -type f -exec sh -c '
for pathname do
pathname=${pathname#./}
aria2c -x 16 -s 1 "https://web.archive.org/save/https://$pathname"
done' sh {} +
Это вызовет дочернюю оболочку с кучей найденных путей. Дочерняя оболочка будет перебирать их и удалять начальный ./
с помощью стандартного раскрытия параметра перед вызовом, в данном случае aria2c
.
В целом:
topdir=/some/directory/path # no '/' at the end
find "$topdir" -type f -exec sh -c '
topdir="$1"; shift
for pathname do
pathname=${pathname#$topdir/}
aria2c -x 16 -s 1 "https://web.archive.org/save/https://$pathname"
done' sh "$topdir" {} +
Связанные: