99 бутылок: mkdir + find
77. mkdir + find — тут некий японец придумал как писать программы, используя только утилиты mkdir и find. Мне такое очень нравится, поэтому и я решил
Программу вы можете видеть на экране, а как она работает расскажу чуть ниже.
# Written by Evgeny Stepanischev https://bolknote.ru
rm -rf bottles; mkdir bottles
find bottles -maxdepth 98 -execdir mkdir bottles/bottles \;
find bottles -empty -name bottles -execdir mkdir bottles/bottle \;
find bottles \
-empty -printf "1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.\n" -o \
-regex '.*/bottles/bottles' \
-execdir find . \
-empty -printf "%d bottles of beer on the wall, %d bottles of beer.\n" \; \
-execdir find bottles \
-empty -printf "Take one down and pass it around, %d %f of beer on the wall.\n\n" \;
# Clean up
rm -rf bottlesПрежде всего — что за две команды тут используются? rm не в счёт, она для очистки мусора, можно без неё.
Команда mkdir, наверное, многим знакома — это создание директория, а find — утилита для поиска файлов и директориев по различным критериям. Причём с найденным она может делать некоторые простые действия.
Чтобы писать программы, автор оригинальной статьи использует несколько находок.
Параметр запускает указанную команду в директории, который сейчас просматривает find. Эти вложенные директории в дальнейшем используются как конечный цикл для следующей команды find. Вложенность при этом можно регулировать параметром -maxdepth.
Мне пришлось дополнительно решить ещё две проблемы.
На самом деле на каждой внешней итерации я пускаю не один, а два внутренних цикла, поскольку мне нужны два числа — текущее значение считаемого «пива» и это же значение, уменьшенное на единицу. Сделать это было просто — ещё один find надо запускать во вложенном директории.
Но в строке перед этим текстом у меня сделано более честно. Как видно, структура директориев у меня такая: 98 раз созданы вложенные bottles, а конечная директория называется bottle.
Это мне позволяет в одном из «циклов», огранизованных через find, использовать аргумент %f параметра -printf, который выводит имя текущего директория. Таким образом в самом конце я получаю bottle вместо bottles.
Добавлено: мне подсказали, что обратный цикл можно огранизовать проще, через ключ -depth, переделал программу под него:
# Written by Evgeny Stepanischev https://bolknote.ru
find start -delete 2>&-
mkdir -p start/bottle/bottles
find start/bottle -maxdepth 97 -name bottles -execdir mkdir bottles/bottles \;
find start -mindepth 1 -depth \
-empty -printf "%d %f of beer on the wall, %d %f of beer.\n" -o \
! -empty -printf "Take one down and pass it around, %d %f of beer on the wall.\n\n" \
-printf "%d %f of beer on the wall, %d %f of beer.\n" \
-name bottle -printf "Take one down and pass it around, no bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.\n"
rm -rf start
Комментарии 4