gpt4 book ai didi

linux - 读取循环时 bash :输出永不改变;被缓存?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:26:37 26 4
gpt4 key购买 nike

***最终答案:

dbus-monitor --profile "interface='net.sacredchao.QuodLibet',member='SongStarted'" |
while read -r line; do
sleep 1
echo -e "$(grep '~filename=' $HOME/.quodlibet/current | sed 's/~filename=//')\n$(python2 -c "import sys, urllib as ul; print ul.unquote_plus(sys.argv[1])" "$(quodlibet --print-queue | sed 's|file://||g')")" > $HOME/Dropbox/Playlists/queue
done

竞态条件和用多个写操作删除一个文件都有问题,而且我还用python命令替换了echo-e,因为qoodlibet是用python生成的,它很可能被解析为一开始我不想用python进行的解析。现在一切正常了。我已经完成了大多数音乐播放器已经具备的Quodlibet功能:一个队列,它可以在程序崩溃时存活下来,而且不需要不断地修改和照看,只需准确地播放每首歌一次。叹息
——原题:
我使用的是ArchLinux,我制作了一个脚本,每次歌曲播放结束/开始时,它都会保存Quodlibet的队列。除了一件事之外,所有的东西都可以工作(所以您不必检查所有sed命令中的错误或任何东西)。如果我在终端中手动运行所有这些东西,而不使用while循环或dbu——只要在每次注意到歌曲结束时手动写入文件——它就可以正常工作。一旦我将它放入while循环,它仍然会在每次歌曲开始时写入文件,但它每次都会写入完全相同的文件,直到我重新启动脚本。我认为它在缓存这些命令的输出,而从不更新缓存。
所以,让我们详细说明一下:Quodlibet有它当前正在播放的歌曲,以及接下来要播放什么的队列。剧本如下:
while read -r line; do
grep '~filename=' $HOME/.quodlibet/current \
| sed 's/~filename=//' > $HOME/Dropbox/Playlists/queue
echo -e "$(quodlibet --print-queue | sed 's|%|\\\x|g' | sed 's|file://||g')" \
>> $HOME/Dropbox/Playlists/queue
done <<< "$(dbus-monitor --profile "interface='net.sacredchao.QuodLibet',member='SongStarted'")"

每次一首歌变了,应该发生的是这两个命令将正在播放的歌和队列写到一个文件中。相反,每次歌曲更改时,这两个命令都会写入当前正在播放的歌曲,并在while循环第一次写入文件时排队。
所以我们假设现在播放的是第一轨,第二轨到第十轨在队列中。脚本将其写入文件。
然后,第一轨结束。现在,播放的是第2首曲目,排队的是第3首到第10首曲目。然而,即使循环注意到歌曲的变化并将其写入文件,它所写入的内容仍然是现在播放的曲目1,以及作为队列的曲目2到10。再一次。你还没来得及知道,它正在播放第10首曲目,队列是空的,但文件中仍然有10首曲目。
当循环脚本运行时,我尝试在循环内手动运行完全相同的命令,我自己,在循环外的终端中,在歌曲更改后立即运行。文件会反映出它应该是什么。但当歌曲再次改变时,循环会捕捉到这一点,并再次重写所有10首曲目。换言之,这些精确的命令只有在循环中时才不会执行我想要的操作。有些东西肯定是被缓存的,从来没有更新过。
编辑:看来我需要澄清一些事情。
1)尽管这不应该是这样,但我的脚本的行为方式完全相同,无论它是:
while read -r line; do
grep '~filename=' $HOME/.quodlibet/current \
| sed 's/~filename=//' > $HOME/Dropbox/Playlists/queue
echo -e "$(quodlibet --print-queue | sed 's|%|\\\x|g' | sed 's|file://||g')" \
>> $HOME/Dropbox/Playlists/queue
done <<< "$(dbus-monitor --profile "interface='net.sacredchao.QuodLibet',member='SongStarted'")"

或:
dbus-monitor --profile "interface='net.sacredchao.QuodLibet',member='SongStarted'" |
while read -r line; do
grep '~filename=' $HOME/.quodlibet/current \
| sed 's/~filename=//' > $HOME/Dropbox/Playlists/queue
echo -e "$(quodlibet --print-queue | sed 's|%|\\\x|g' | sed 's|file://||g')" \
>> $HOME/Dropbox/Playlists/queue
done

2)在引入更复杂的内容之前,我测试了一个更简单的版本。这是我写的剧本:
while true; do
echo "$(cat /tmp/foo | sed 's/b/n/g')"
done

我尝试在循环运行的过程中更改文件/tmp/foo,就像qoodlibet命令的输出会自行更改一样,并且它更新得很好。输出改变了。
这不是我一开始就写的,但这是我在开始真正的剧本之前做的最后一个。您将看到它包含了我正在做的所有事情,除了4件事:qoodlibet、dbus命令、>保存或>>附加到文件,以及while read组合。其中之一就是无论环境发生什么变化,输出都保持不变,我认为我们可以排除qoodlibet,因为正如我之前所说,手动运行这些命令可以很好地工作。
编辑2:好吧,我没有在文件上向下滚动,但我刚才已经滚动了。这个问题变得更复杂,但可能更容易解决。它不是每次都写完全相同的输出。它不知何故跳过了覆盖文件的那一行——以grep开头的那一行——而只是附加了第二行echo-e的输出。
编辑3:现在我又被难住了。当我从while循环中复制并粘贴精确的两行代码到bash终端中时,它们会按照我的要求执行。但在while循环中,第一个grep命令从未真正写入该文件。我想可能是因为它莫名其妙地吃掉了第一个命令,所以我试着事先添加了一个空的回声:
dbus-monitor --profile "interface='net.sacredchao.QuodLibet',member='SongStarted'" |
while read -r line; do
echo
grep '~filename=' $HOME/.quodlibet/current \
| sed 's/~filename=//' > $HOME/Dropbox/Playlists/queue
echo -e "$(quodlibet --print-queue | sed 's|%|\\\x|g' | sed 's|file://||g')" \
>> $HOME/Dropbox/Playlists/queue
done

但它还在吃第一个果冻。为什么不保存文件?
编辑4:我已经确认grep命令确实输出了正确的输出,但是不会将其写入文件。

最佳答案

为了把你想做的具体事情和你感觉到的问题分离开来,我建议在尝试使用任何花哨的东西之前先尝试一些独立的命令。

while read -r line ; do
echo $line
done <<< $(yes)

注意,这不会输出任何内容。 $(yes)提供的输入永远不会完成,因此外部循环将永远不会打印任何内容。至少有一条评论指出了这一点。
不要使用捕捉变量,而是尝试将输出直接管道到循环。我不能说这对您有用,但它至少解决了流输出到while循环的一个明显问题。
yes | while read -r line ; do
echo $line
done

基于这里的其他调试工作,问题似乎是发送给dbus的关于歌曲转换的信号和将新的“当前”歌曲写入磁盘之间的竞争条件。为了提供更完整的解决方案(当然是未经测试的),我可以从以下几点开始:
function urldecode() {
python -c "import sys, urllib as ul; print ul.unquote_plus(sys.argv[1])" "$@"
}

dbus-monitor --profile "interface='net.sacredchao.QuodLibet',member='SongStarted'" | \
while read -r line; do
sleep 1 # Adjust as necessary to preventing race conditions
$CurrentSongFile=$(grep '~filename=' $HOME/.quodlibet/current | sed 's/~filename=//')
$SongFileQueue=$(urldecode "$(quodlibet --print-queue)") | sed 's_file://__g')
printf "$CurrentSongFile\n$SongFileQueue" > $HOME/Dropbox/Playlists/queue
done

关于linux - 读取循环时 bash :输出永不改变;被缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33860537/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com