Bash · 19.04.2024

Bash, JSON и прочие сложности

Уютный астраханский вечер с постпика приветствует всех, кто ещё не спит в эту пятницу.

Всё описанное ниже проводилось на операционной системе Linux Lubuntu 16.04, но это не значит, что в рамках других версий и дистрибутивов методы не являются рабочими. Здесь тег про Lubuntu, а здесь можно скачать его дистрибутив.

Решил окончательно добить тему динамической установки обоев рабочего стола в Linux с помощью скриптов и больше к ней не возвращаться. Заодно протестировал метод работы с JSON из среды bash с использованием пакета jq (официальная документация где-то здесь, тётя Вика в курсе, но, как всегда, в общих чертах, а здесь статья из Хакера). Итак, очередное приключение на 20 минут. Буквально, туда и обратно.

За основу была взята история из этого поста с PowerShell и API. Там я экспериментировал с api peapix (Free Bing Image API) и напомню, что…

The images are provided for wallpaper use only.

Для реализации функционала в Linux нужно было перевести простенький PS1 в bash, но сразу «под ключ» — чтобы и скачать, и фон установить. По ряду причин, установка pwsh мною вообще не рассматривалась.

Покопавшись в дебрях bash, я так и не смог найти ничего изкоробочного для внятной работы с json. Есть методы по парсингу и фильтрации подстрок, но это бы заняло значительное время и не выглядит, как универсальное решение. Мне же было нужно что-то аналогичное функционалу ConvertFrom-Json из вселенной PowerShell.

Именно такой удобной штуковиной и оказалась утилита jq. Ей смело можно скормить вывод curl с помощью конвейера.

Установить jq можно с помощью команды:

sudo apt install jq

После установки приступаем к экспериментам. Обрисовав логику работы будущего скрипта, мне подумалось, что было бы неплохо сначала проверить — установлена ли утилита jq в системе и что делать, если она отсутствует. Всё остальное вполне удобно помещалось в функцию getbingwalls и вызывать её стоило бы только в случае наличия jq.

При отсутствии jq — в консоль рухнет рекомендация по её установке. Хотя в дальнейшем никто не мешает запихнуть туда и команду установки, и вызов основной функции скрипта. А можно и вообще пойти путём юношеского максимализма и выполнять проверку внутри функции.

Весь скрипт выглядит так:

#!/bin/bash
# sudo chmod +x /scripts/wallpapers.sh

# Основная функция скрипта
getbingwalls()
{
	# URL API
	url="https://peapix.com/bing/feed"

	# Папка с обоями
	dir="wallpapers"

	# Создать папку если её нет и перейти в неё
	cd $(dirname "$0")
	mkdir -p $dir
	cd $(dirname "$0")/$dir
	
	# Получаем ссылки из JSON
	links=$(curl -s $url | jq -r '.[].imageUrl')
	
	# Цикл скачивания файлов
	for link in $links
	do
		# Получение имени файла из URL
		filename=$(basename "$link")
		
		# Скачивание файла, если его нет в папке
		if [ ! -f $filename ]
		then
			echo "Cкачивается файл $link..."
			curl -O $link --silent	
		fi
	done
	
	# Получаем случайный файл в папке
	randomfile=$( find -type f -print0 | shuf -z -n 1 )
	
	# Получаем полный путь случайного файла
	getpath=$(readlink -f $randomfile)
	
	# Устанавливаем случайный файл фоном рабочего стола
	# Используется PCManFM
	pcmanfm --set-wallpaper=$getpath
}

# Проверить установлен ли пакет JQ
if command -v jq > /dev/null
then
	# Пакет установлен
    getbingwalls
else
	# Пакет не установлен
	echo "Отсуствует пакет jq для работы с JSON!"
	echo "Попробуйте его установить с помощью команды sudo apt install jq"
fi

Я постарался по максимуму снабдить код комментариями, чтобы было понятно — что делает та или иная команда. Специально не стал делать функцию чистки папки по временным критериям отбора. Подобную фичу можно встретить в коде вот этого скрипта.

Отдельно опишу только две экстравагантные вещи. Для начала — работу с json в этом блоке:

links=$(curl -s $url | jq -r '.[].imageUrl')

В переменную links помещаются ссылки из imageUrl (для понимания атрибутов, передаваемых jq, читаем json ещё раз). Далее следует цикл скачивания с проверкой наличия файла в каталоге. Получаем имя целевого файла из url с помощью команды basename. Если файл есть — не делаем ничего и двигаемся дальше по скрипту.

И в завершении — получаем путь случайного файла из папки с изображениями и передаём его файловому менеджеру для установки фоном рабочего стола. Присваивание переменной имени случайного файла было осуществлено с помощью команд find и shuf:

randomfile=$( find -type f -print0 | shuf -z -n 1 )

Если с find всё понятно, то shuf — это генератор случайных перестановок. Здесь эта команда выступает в роли ведущего «Русского лото». Ну, который бочонки из мешка вытаскивает. Только в нашём случае вместо мешка — каталог, а вместо бочонка — файл.

Скачать скрипт из терминала можно с помощью утилиты wget:

sudo wget -P /scripts https://ngdream.ru/wallpapers.sh

Обратите внимание, что скрипт скачается в папку scripts в корне файловой системы. Если папки нет — утилита её создаст.

После скачивания нужно сделать скрипт исполняемым:

sudo chmod +x /scripts/wallpapers.sh

Кстати, этот код также упомянут в качестве комментария в самом скрипте.

И, как водится, кнопка для скачивания: