所以,我在 Arch Linux 上运行 i3 我有一个幻灯片脚本,每 5 秒更改一次背景。我有一堆信号,例如切换、下一个、上一个、更快、更慢。我将所有信号脚本绑定到一个键。
启动/终止幻灯片也绑定到一个键。事实上,我有一个父脚本列表,它可以实现
这允许我使用不同的键开始不同的幻灯片。
我有一个主循环,在它的末尾,我想在循环重新运行之前放置一个“wait”$timer 命令并转到下一个循环。
但是我希望这个“等待”命令可以被其他脚本发送的信号中断。
睡眠不会被中断,所以除非我循环运行睡眠0.00001s,这会杀死信号点,否则当我按下一个或上一个时,它不会实时做出反应。
终端中的超时可以执行,但在脚本内,它甚至无法执行 : 命令,它缺少权限。
read -t $timer 从终端启动时运行良好 ,但一旦从其他事情开始,它就崩溃了。
我尝试从子 shell 中读取,读取 << /dev/null, none of it worked.
这就像如果读,读到一个空集,而不是真正什么都没有。
我不知道人们如何在脚本中将信号与计时器混合,但我确信它一定在 bash 的能力范围内。
我希望得到任何帮助。
这是代码。
#!/bin/bash
notify-send "Started Slideshow" -t 3000
timer=5 # seconds
# Function to change background using feh
change_background() {
feh --bg-center --bg-fill --no-fehbg "$1"
}
# Default directory containing original images (if no path provided)
default_image_dir="Cool Pictures"
# Function to handle signals and manage natural cycling
signal_handler() {
case $1 in
"next")
printf "Received next signal\n\n"
next_image=true
;;
"previous")
printf "Received previous signal\n\n"
prev_image=true
;;
"toggle")
notify-send 1
if [ $slideshow_playing = true ] ; then
slideshow_playing=false
else
slideshow_playing=true
fi
printf "Received toggle signal\n"
printf "The slideshow is playing? $slideshow_playing \n\n"
;;
"faster")
printf "Recieved faster signal\n\n"
timer=$(echo "$timer / 1.1" | bc -l)
echo "new timer is $timer"
;;
"slower")
echo "Recieved slower signal"
timer=$(echo "$timer * 1.1" | bc -l)
echo "new timer is $timer"
;;
*)
echo "Unknown signal: $1"
;;
esac
}
time_step=0.1
wait_until_timer() {
local start_time=$(date +%s)
local timer=$1
local current_time
local elapsed_time
while true; do
current_time=$(date +%s)
elapsed_time=$((current_time - start_time))
if [ $elapsed_time -ge $timer ]; then
break
fi
sleep $time_step # Adjust sleep duration as needed
done
}
# Set up signal handlers
trap 'signal_handler "next"' SIGRTMIN+1
trap 'signal_handler "previous"' SIGRTMIN+2
trap 'signal_handler "toggle"' SIGRTMIN+3
trap 'signal_handler "faster"' SIGRTMIN+4
trap 'signal_handler "slower"' SIGRTMIN+5
# Arguments and directories setup
echo "arg 0: $0"
echo "arg 1: $1"
echo "arg 2: $2"
echo "arg 3: $3"
resized_dir=$2
true_dir="$HOME/Pictures/Desktop Background Slideshow/${1:-$default_image_dir}/$resized_dir"
# Initial setup or any other initialization logic can go here
printf "Reading from $true_dir \n\n"
# Shuffle images and store in an array
shuffle_images() {
mapfile -d '' shuffled_images < <(find "$true_dir" -type f -print0 | shuf -z)
total_images=${#shuffled_images[@]}
}
shuffle_images
i=0
slideshow_playing=true
# Main loop for natural cycling
while true; do
if [ "$next_image" == true ]; then
next_image=false
single_play=true
((i++))
if [ $i -ge $total_images ]; then
i=0
fi
elif [ "$prev_image" == true ]; then
printf "Previous image received, i=$i\n"
prev_image=false
single_play=true
((i--))
if [ $i -lt 0 ]; then
i=$((total_images - 1))
fi
elif [ $slideshow_playing = false ]; then
#we pause here. double check to avoid indentation
: # do nothing
else
((i++))
if [ $i -ge $total_images ]; then
i=0
fi
fi
if [ $slideshow_playing = true ] || [ $single_play = true ] ; then
image="${shuffled_images[$i]}"
if [ "$3" == "none" ]; then
echo "Setting background to: $image"
fi
if ! [ -n "$2" ]; then
printf "Changing to $image \n\n"
fi
change_background "$image"
single_play=false
fi
# Use read with timeout for natural cycling and signal interruption
#wait_until_timer $timer
wait $timer
done
如果我理解正确的话,您的脚本中有一个主循环,并且您希望它在计时器上或在调用信号时执行任务。
这确实可以使用 read 来完成,但是您需要将其连接到管道。 以下是如何使用 FIFO 执行此操作的示例:
#!/bin/bash
set -eu
shopt -s failglob
FIFO=test.FIFO # can be changed to whatever
mkfifo "${FIFO}" # create a fifo
trap 'rm "${FIFO}"' EXIT # clean fifo at end of script
trap 'echo > "${FIFO}"' SIGUSR1 # write to fifo: this will unblock read from fifo
while true
do
echo hello! # do stuff here
# this will wait for either 1s or for someone to write to fifo
read -t 1 <> "${FIFO}" || true # remark: <> "${FIFO}" => because any process connected to fifo cannot start until the fifo is opened for both read and write
done # remark2: || true => because read will fail on timeout and I always use set -e in my scripts