Драка снимается перемешиванием. Рабочий читает список, тасует его и идёт в своём порядке, тогда вероятность столкнуться падает до мелочи.
vzyat_zadachu() {
for f in $(ls ochered/novye | shuf); do
if mv "ochered/novye/$f" "ochered/v-rabote/$f.$$" 2>/dev/null; then
printf '%s\n' "ochered/v-rabote/$f.$$"
return 0
fi
done
return 1
}
Номер процесса в имени пригодится дальше. Рабочий умер, его файлы остались в v-rabote, и уборщик по расписанию возвращает в novye всё, что старше получаса и чей процесс уже мёртв.
Второй приём для тех, кому четыре каталога кажутся грубыми: журнал с дописыванием. Файл только растёт, каждая строка это событие, взято или сделано. Состояние очереди собирается прочтением журнала с начала. Короткая строка под O_APPEND дописывается атомарно, поэтому четыре процесса пишут в один файл спокойно. Минус тоже понятный: журнал надо периодически сворачивать, иначе он пухнет без конца.
Каталог понятнее глазами, журнал быстрее на мелких задачах. На нескольких тысячах строк я бы взял каталог и не думал.
конфиг без комментария это загадка