1
votes

EDIT: I don't know if this problem will ever be solved, but it might not matter anymore. I also asked the quodlibet team for help, and they responded by immediately fixing the program to allow escaped commas, and telling me about the ~/.quodlibet/control file (which is what fixed it for me).

So, I'm running a command to automatically enqueue a list of files into quodlibet (a music player): I've tested it in bash and fish.

quodlibet --enqueue-files="\"$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|","|g')\""

and the fish version is:

quodlibet --enqueue-files=\"(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|","|g')\"

I've been happily using this exact bash command for a few weeks now, and it's been working perfectly fine. However, it's suddenly stopped working. And here's the weirdest part. I have two computers running Arch Linux. There's one that I keep updated regularly, the desktop, and one that I haven't bothered to upgrade in quite a while, the laptop. It has slightly older versions of quodlibet, bash, and fish. I went away for a while with just my laptop, and kept happily using this command. But, a few days ago, without me upgrading or changing anything about quodlibet, bash, fish, the command, or even the entire system in general, it suddenly stopped working. I've now returned home to the upgraded desktop, and it's now not working, either, as if this entire problem is based on the system clock or something.

So how exactly is it not working? Well, it does absolutely nothing and spits out no output. It's supposed to spit out no output if it works, but it's not working, and there seem to be no errrors. But, here's where it gets extra weird. It actually does still work fine, IF I split it into two commands. If I run

echo "\"$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|","|g')\""

then copy the output and paste it into quodlibet --enqueue-file=, it works.

Example: Let's say the file, $HOME/Dropbox/Playlists/queue, has 3 music files in it:

/home/jimi/Music/Song1.mp3
/home/jimi/Music/Song2.mp3
/home/jimi/Music/Song3.mp3

The string "\"$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|","|g')\"" evaluates that to

"/home/jimi/Music/Song2.mp3","/home/jimi/Music/Song3.mp3"

(The first song starts playing, rather than getting enqueued, thanks to a different command.) If I try to enqueue the string "\"$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|","|g')\"", which has worked until a few days ago, it doesn't work. But, if I manually paste in "/home/jimi/Music/Song2.mp3","/home/jimi/Music/Song3.mp3", it works fine. I have no idea why this is. I've done a bunch of tests to try to figure it out and have gotten nowhere. The two tests I've done of major note are trying it in fish to find the exact same behavior, and trying

quodlibet --enqueue-files=$(echo "\"$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|","|g')\"")

since it seemed to like echo's output so much. But, neither work. Bottom line, quodlibet has decided to only accept files that I manually type in myself, even though thanks to the way bash works, it shouldn't be able to tell whether I typed it in myself.

EDIT: New news: the quotes are the root of the problem. If I run

quodlibet --enqueue-files="$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|,|g')"

it works. What's the difference? Well, that string avoids having any quotes be involved in the sed string. I know it's specifically the sed quotes (sed ':a;N;$!ba;s|\n|","|g') because I already tested it without the other quotes. Anyway, the sed quotes. When I remove those, it works. That isn't a viable solution, because in order for quodlibet to not misinterpret any songs that have commas in their filename, I need those quotes there. I can't escape the comma--it doesn't accept that. So, I tried this:

\"$(tail -n +2 $HOME/Dropbox/Playlists/queue | sed ':a;N;$!ba;s|\n|\",\"|g')\"

but that doesn't work, either! It seems quodlibet will not accept anything that has quotes in the sed line! And when I tried it with escaped single quotes, bash would give me a newline, as if the command wasn't finished being typed out.

1
Unless Quod Libet explicitly and oddly requires you to use literal double quotes around the file name list, the \" looks very wrong. Most places you see quotes in shell script, they are there for the shell, and handled by the shell, e.g. to ensure that an argument is passed in as a single string.tripleee
@tripleee It requires me to. Otherwise, songs that have commas in their filenames will be interpreted as two separate files. Escaping the comma doesn't work, so I have to put quotes around each file. I know, the syntax for --enqueue-files= is terrible. I agree. And it doesn't match up with the syntax of any other quodlibet command. I don't know what's up with that.Jimi-James
@tripleee You're on the right track, though. You just helped me discover a lead. I'll edit my post with it.Jimi-James
@Jimi-James The syntax of that command is a little hacky, yes (I wrote it), but there's some good background to why here: github.com/quodlibet/quodlibet/issues/716declension
@NickB Yeah, I see now. Sorry for my language.Jimi-James

1 Answers

1
votes

I don't think you've got this right. I'll have to confess that I don't know Fish, but for Bash, what you are saying isn't really making sense.

When you are pasting "...", the shell peels off the quotes. Witness:

vnix$ printf '>>%s<<\n' "/home/jimi/Music/Song2.mp3","/home/jimi/Music/Song3.mp3"
>>/home/jimi/Music/Song2.mp3,/home/jimi/Music/Song3.mp3<<

If you really, really want to preserve those quotes, you need to escape, or somehow otherwise interpolate them. Perhaps like this:

vnix$ printf '>>%s<<\n' '"/home/jimi/Music/Song2.mp3","/home/jimi/Music/Song3.mp3"'
>>"/home/jimi/Music/Song2.mp3","/home/jimi/Music/Song3.mp3"<<

Now, the single quotes protect the double quotes from being processed by the shell, and so they make it through to the printf command's arguments.

Assuming you do want Quod Libet to see literal quotes around each file name, you can read them from the file like so:

quodlibet --enqueue-files="$(sed '1d;:a;N;$!ba;s|\n|","|g;s/.*/"&"/' $HOME/Dropbox/Playlists/queue)"

(I took the liberty to factor out the tail since sed can remove the first line just fine.) Try the same with printf to see what we are getting here:

vnix$ printf '>>%s<<\n' quodlibet --enqueue-files="$(sed -e 1d \
    -e ':a' -e 'N' -e '$!ba' -e 's|\n|","|g' -e 's/.*/"&"/' quodlibet)"
>>quodlibet<<
>>--enqueue-files="/home/jimi/Music/Song2.mp3","/home/jimi/Music/Song3.mp3"<<

(My crufty BSD sed doesn't like semicolons in jump labels, it seems?)

The shell eats the outer double quotes, and the sed script now supplies all the literal quotes we need the argument to actually contain.

I'm not convinced that this will work, but it should provide the answer to the question you appear to be asking.