我希望我的壁纸具有季节特色(夏季、秋季、冬季、春季),而且每天更新季节主题壁纸。
因此,本质上,我打算有 4 个目录( )。在夏季,我的壁纸背景会每天summer, fall, winter, spring
轮换目录中的图像。然后在 9 月 21 日,壁纸目录将更改为,然后壁纸将每天循环显示这些图像,依此类推。summer
fall
我很乐意编写脚本,但是我该从哪里开始呢?
这个问题有何独特之处
编辑:进一步澄清是什么使这个问题变得独特。虽然创建幻灯片的方法有很多,但它们都依赖于设置图像目录。我问的是如何动态更改图像目录。因此,今天的幻灯片放映来自目录/images/winter/
,春季的幻灯片放映来自目录/images/spring/
。我可以通过在每个季节更改外观设置中的目录来手动执行此操作,但当我可以让计算机为我执行此操作时,我不想这样做。
答案1
介绍
基本问题是如何在春季、夏季、秋季和冬季开始时做某事。为此,我将创建一个在启动时运行的 bash 脚本,而不是用cron
条目堵塞。
我使用 OP 的问题“如何开发脚本?”来回答这个问题。因此,我偏离了通常的简单发布 bash 脚本的方法,而是通过以下方式增强了答案:
- 代码中包含参考资料。它们链接到 Stack Exchange 解答以解决特定问题。例如:如何复制文件、如何获取一年中的某一天等。
- 提供了“测试”部分,因为这是我们每个人都需要做的事情
- 之所以提供“增强功能”部分,是因为软件通常以新版本进行开发,每个版本都比前一个版本有所改进。
季节什么时候开始?
来自农民年鉴:
2018 年的季节
季节 | 天文起点 | 气象开始 |
---|---|---|
春天 | 3 月 20 日星期二下午 12:15(美国东部时间) | 3 月 1 日,星期四 |
夏天 | 6 月 21 日星期四,上午 6:07(美国东部夏令时间) | 6 月 1 日,星期五 |
落下 | 9 月 22 日星期六,晚上 9:54(美国东部夏令时间) | 9 月 1 日,星期六 |
冬天 | 星期五,12 月 21 日,下午 5:23(美国东部时间) | 12 月 1 日,星期六 |
将季节开始日期转换为一年中的某一天
为了使我们的bash
脚本正常工作,我们需要知道每个季节从哪一天开始。
$ echo $(date --date="March 20" '+%j')
079
$ echo $(date --date="June 21" '+%j')
172
$ echo $(date --date="Sep 22" '+%j')
265
$ echo $(date --date="Dec 21" '+%j')
355
# Reference: https://unix.stackexchange.com/questions/352176/take-input-arguments-and-pass-them-to-date
创建 bash 脚本:season.sh
使用以下方法打开终端:Ctrl++AltT
如果目录不存在则创建该目录:mkdir -p ~/bin
使用以下方法编辑脚本:gedit ~/bin/season.sh
- 笔记:Lubuntu 用户需要
leafpad
使用gedit
将以下行复制并粘贴到gedit
:
#!/bin/bash
# NAME: season.sh
# PATH: ~/bin
# DATE: December 15, 2018
# NOTE: Written for: https://askubuntu.com/questions/1100934/change-dynamic-wallpaper-directory-every-season/1102084#1102084
# User defined variables, change to suit your needs
# Our directory names, lines indented for cosmetic reasons only
SlideShowDir="~/Season Slide Show"
SpringDir="~/Pictures/Spring Slide Show"
SummerDir="~/Pictures/Summer Slide Show"
FallDir="~/Pictures/Fall Slide Show"
WinterDir="~/Pictures/Winter Slide Show"
CheckTripWire () {
# Our last season is in "~/Season Slide Show/CurrentSeason"
LastSeasonFilename="$SlideShowDir"/CurrentSeason
LastSeason=$(cat "$LastSeasonFilename")
[[ "$LastSeason" == "$Season" ]] && return 0 # Season still the same
# We now know our season has changed.
rm -f "$SlideShowDir"/{*,.*} # Erase all files in target
# Reference: https://askubuntu.com/questions/60228/how-to-remove-all-files-from-a-directory
echo "$Season" > "$LastSeasonFilename" # Record new season in target
# Copy new slide show based on season
if (( "$Season" == SPRING)) ; then
cp -R "$SpringDir"/. "$SlideShowDir"/
# Reference: https://stackoverflow.com/questions/3643848/copy-files-from-one-directory-into-an-existing-directory
elif (( "$Season" == SUMMER)) ; then
cp -R "$SummerDir"/. "$SlideShowDir"/
elif (( "$Season" == FALL)) ; then
cp -R "$FallDir"/. "$SlideShowDir"/
else
cp -R "$WinterDir"/. "$SlideShowDir"/
fi
} # End of CheckTripWire () function.
# Start of Mainline
DOY=$(date '+%j') # DOY = Current Day of Year
# Reference: https://stackoverflow.com/questions/10112453/how-to-get-day-of-the-year-in-shell
if ((DOY>=079 && DOY<172)) ; then
Season="SPRING" # Spring has sprung!
# Reference: https://stackoverflow.com/questions/12614011/using-case-for-a-range-of-numbers-in-bash
elif ((DOY>=172 && DOY<265)) ; then
Season="SUMMER" # Hit the beach!
elif ((DOY>=265 && DOY<355)) ; then
Season="FALL" # Rake those leaves!
else
Season="WINTER" # Shovel the snow!
fi
# Current season establish, now see if we tripped the wire
CheckTripWire
exit 0 # Command not necessary but good habit to signify no Abend.
将文件保存在 中gedit
。现在使用以下命令将其标记为可执行文件:
chmod a+x ~/bin/season.sh
接下来我们需要将其添加到启动应用程序中。参考:如何在登录时自动启动应用程序?
笔记:您可能已经在启动应用程序中设置了幻灯片放映。您将需要使用season.sh
前您的常规幻灯片放映,因为它会删除并复制文件,如果幻灯片放映程序首先启动,这会导致幻灯片放映程序崩溃。
测试
您将希望season.sh
在创建脚本时对其进行测试,而不是等待一年来查看它是否正常运行。参考:伪造特定 shell 会话的日期
增强功能
最初开发脚本后,通常会在几天、几周、几个月甚至几年后对其进行改进。本节讨论您可能希望在session.sh
以后进行的一些改进。
压缩文件以节省磁盘空间
考虑将淡季图像压缩为柏油(磁带存档)格式以节省磁盘空间。然后用解压文件的命令替换cp
(复制)命令。参考:tar
23 个 Linux 的 tar 命令示例:
例如,我们将改变:
cp -R "$SpringDir"/. "$SlideShowDir"/
到:
tar -xf "$SpringDir"archive.tar -C "$SlideShowDir"/
...其他季节也是如此。
设置赛季开始的变量
使用变量表示赛季开始日期可以更轻松地修改脚本,并使代码更易于阅读(又名代码可读性)。
考虑设置赛季开始的变量:
SpringStart=079
SummerStart=179
FallStart=265
WinterStart=355
在脚本顶部定义变量,使它们更容易发现和更改。您可能希望对闰年这样做。您可能希望将季节开始日期更改为“气象”日期,而不是“天文”日期。
然后更改以下几行:
if ((DOY>=079 && DOY<172)) ; then
elif ((DOY>=172 && DOY<265)) ; then
elif ((DOY>=265 && DOY<355)) ; then
对此:
if ((DOY>="$SpringStart" && DOY<"$SummerStart")) ; then
elif ((DOY>="$SummerStart" && DOY<"$FallStart")) ; then
elif ((DOY>="$FallStart" && DOY<"$WinterStart")) ; then
答案2
也许这是一个更简单的方法:
~/images/mybackgrounds
创建从到 的符号链接~/images/spring
:ln -s ~/images/spring ~/images/mybackgrounds
使用这些方法之一显示使用来自的图像的背景幻灯片
~/images/mybackgrounds
。设置 crontab 条目以在特定日期更改符号链接。创建一个名为的文件,
~/mycrontab
其内容如下:# min hr day mon dow 0 9 21 3 * ln -sf ~/images/spring ~/images/mybackgrounds 0 9 21 6 * ln -sf ~/images/summer ~/images/mybackgrounds 0 9 21 9 * ln -sf ~/images/fall ~/images/mybackgrounds 0 9 21 12 * ln -sf ~/images/winter ~/images/mybackgrounds
跑步
crontab ~/mycrontab
注册 crontab 条目。3 月 21 日上午 9 点,
crond
将运行以下命令ln -sf ~/images/spring ~/images/mybackgrounds
因此链接~/images/mybackgrounds
到~/images/spring
。6 月 21 日上午 9 点,
crond
将更改符号链接,使~/images/mybackgrounds
指向
~/images/summer
。幻灯片程序配置为从 中选择一个文件
~/images/mybackgrounds
。 到 的路径~/images/mybackgrounds
保持不变,但现在所有内容都不同,因为符号链接指向不同的位置。9 月 21 日和 12 月 21 日的 crontab 条目使用了同样的技巧。
答案3
步骤 1:创建 slideshow.py 脚本
~/bin/slideshow.py
将其保存在名为:的文件中。
#!/usr/bin/env python
import os
import datetime as DT
import itertools as IT
import bisect
import random
import subprocess
# customize cutoffs and image_dirs however you like, but note that there must be
# the same number of items in each, and the items in cutoffs must be in sorted order.
cutoffs = [(3, 21), (6, 21), (9, 21), (12, 21)]
image_dirs = ['~/images/winter', '~/images/spring', '~/images/summer', '~/images/fall']
image_dirs = list(map(os.path.expanduser, image_dirs))
today = DT.date.today()
year = today.year
# convert the cutoffs to actual dates
cutoff_dates = [DT.date(year, m, d) for m, d in cutoffs]
# find the index into cutoff_dates where today would fit and still keep the list sorted
idx = bisect.bisect(cutoff_dates, today)
# use idx to get the corresponding image directory
image_dir = next(IT.islice(IT.cycle(image_dirs), idx, idx+1))
# list all the files in image_dir (even in subdirectories, and following symlinks)
files = [os.path.join(root, filename)
for root, dirs, files in os.walk(image_dirs[idx], followlinks=True)
for filename in files]
# pick a file at random
imagefile = os.path.abspath(random.choice(files))
# find the current process's effective user id (EUID)
euid = str(os.geteuid())
# find the pid of the current EUID's gnome-session
pid = subprocess.check_output(['pgrep', '--euid', euid, 'gnome-session']).strip().decode()
# load all the environment variables of gnome-session
env = open('/proc/{}/environ'.format(pid), 'rb').read().strip(b'\x00')
env = dict([item.split(b'=', 1) for item in env.split(b'\x00')])
# get the value of DBUS_SESSION_BUS_ADDRESS environment variable
key = b'DBUS_SESSION_BUS_ADDRESS'
env = {key: env[key]}
# call gsettings to change the background to display the selected file
# with the DBUS_SESSION_BUS_ADDRESS environment variable set appropriately
subprocess.call(['gsettings', 'set', 'org.gnome.desktop.background', 'picture-uri',
'file://{}'.format(imagefile)], env=env)
第 2 步:使其可执行:
chmod 755 ~/bin/slideshow.py
要测试一切是否按预期运行,您可以打开终端并
slideshow.py
重复运行。您应该会看到背景发生变化。请注意, 根据季节的不同,在、 、或slideshow.py
4 个目录之一中查找图像。~/images/spring
~/images/summer
~/images/fall
~/images/winter
步骤3:配置crontab
您可以使用计划任务定期运行命令来更改背景,例如每天一次或每分钟一次。
创建一个名为的文件~/mycrontab
,并在里面放入如下内容:
# min hr day mon dow
# 0 9 * * * ~/bin/slideshow.py # run once at 9AM
* * * * * ~/bin/slideshow.py # run once every minute
然后运行
crontab ~/mycrontab
将更改注册到你的 crontab。
现在您应该看到背景每分钟变化一次。(您甚至可能喜欢保持这种状态。)
crontab
将忽略以 开头的行#
。因此,如果您希望背景每天更改一次,请取消注释第二行并注释掉第三行,这样~/mycrontab
现在看起来就像这样:
# min hr day mon dow
0 9 * * * ~/bin/slideshow.py # run once at 9AM
# * * * * * ~/bin/slideshow.py # run once every minute
但请注意,仅当您当天上午 9 点登录机器时,cron 才会运行此命令。
答案4
好的。以下是我对 Ubuntu 18+ 用户的看法(不确定以前的版本,因此这是一个免责声明)。
在 Ubuntu 中,可以创建一个自定义 XML 文件,其中包含指向图像的路径、“持续时间”和开始时间部分。例如:
<background>
<starttime>
<year>2000</year>
<month>3</month>
<day>21</day>
<hour>00</hour>
<minute>00</minute>
<second>00</second>
</starttime>
<static>
<duration>30.00</duration>
<file>/home/martin/Pictures/Slideshow/spring.jpg</file>
</static>
<static>
<duration>30.00</duration>
<file>/home/martin/Pictures/Slideshow/summer.jpg</file>
</static>
</background>
在此示例中,时间duration
为 30 秒,开始日期/时间是 2000 年 3 月 21 日。只需添加更多具有正确持续时间的图片... 因此计算从 3 月 21 日到 6 月 21 日的秒数,并将此数字放在第一<duration>
部分。然后对 6 月 21 日到 9 月 21 日执行相同操作,并将其放在第二部分。秋季和冬季也是如此。