【发布时间】:2016-02-24 22:32:27
【问题描述】:
***最终答案:
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,因为 quodlibet 是用 python 制作的,它可能被解析为我不知道的解析首先要使用python。现在一切正常。我已经完成了大多数音乐播放器已经拥有的 quodlibet 功能:一个队列实际上可以在程序崩溃后幸存下来,并且不需要不断地修补和照看每首歌曲只播放一次。 叹息
------------原问题:
我正在使用 Arch Linux,并且我制作了一个脚本,该脚本应该在每次歌曲完成/开始播放时保存 quodlibet 的队列。除了一件事之外,一切都有效(因此您不必检查所有这些 sed 命令是否有错误或任何东西)。如果我在终端中手动运行所有这些东西,没有任何 while 循环或 DBus——每次我注意到歌曲结尾时手动写入文件——它工作正常。一旦我把它放在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 循环写入文件的第一次时间排队。
假设现在正在播放的是第 1 首曲目,第 2 到第 10 首曲目在队列中。脚本将其写入文件。
然后,轨道 1 结束。现在,正在播放的是轨道 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,就像 quodlibet 命令的输出会自行更改一样,并且更新得很好。输出发生了应有的变化。
这不是我开始的,但这是我在开始实际脚本之前制作的最后一个。你会看到它包含了我正在做的所有事情,除了 4 件事:quodlibet、dbus 命令、>保存或>>附加到文件,以及 while-read 组合。其中之一是无论环境发生什么变化,输出始终保持不变,我认为我们可以排除 quodlibet,因为正如我之前所说,手动运行这些命令可以正常工作。
编辑 2:Welp,我没有向下滚动文件,但我刚刚做了。这个问题变得更加复杂,但可能更容易解决。它根本不是每次都写完全相同的输出。它以某种方式跳过了覆盖文件的行 - 以 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
但它仍在吃第一个 grep。为什么不保存文件?
编辑 4:我已确认 grep 命令肯定输出正确的输出,但不会将其写入文件。
【问题讨论】:
-
如果您不关心文件而只是在循环中运行
quodlibet命令,您会看到正确的队列输出还是原始输出?因为这是真正的问题。该命令是否在那里工作。同样,current文件是否按照您期望的方式实时更改。 -
您确定它实际上在运行循环吗?
<<< "$(dbus-monitor ... )"部分应该捕获dbus-monitor命令的整个输出,并一次性将其全部输入循环,而不是在歌曲结束时一次一行地输入。尝试在循环顶部添加 `echo "line = '$line'",看看会发生什么。 -
@EtanReisner 是的,如果我不关心文件,这些命令会改变。我在OP中说过几次。 (哇,我希望回车键不一定会发布评论;这让我感到惊讶)
-
@GordonDavisson 我所拥有的是我从寻找如何做 DBus 的事情,然后是如何运行一个 while 循环而不是每次迭代都将它管道到一个单独的 fork 中拼凑起来的东西(这是什么我起初尝试过,结果与我现在的结果完全相同)。我所知道的是,我所做的实际上是在每次歌曲更改时再次运行循环。我已经测试过了。
-
将 grep 输出转储到标准输出。将所有内容转储到标准输出。通过一块一块地撕开它来调试它。如果您的 grep 输出不起作用,则说明您的查询有问题,或者文件不存在(在那个时间点)处于您期望的状态。
标签: linux bash while-loop audio-player