You are not logged in.

#1 2008-11-07 05:05:40

fflarex
Member
Registered: 2007-09-15
Posts: 466

why does this work? (dmenu_run shell script...)

I'm very confused at what this is doing. dwm knowledge would help to understand my question. I don't understand how this script can take a font name with a space in it, the way dwm's default config does, and understand it as one argument.

#!/bin/sh
exe=`dmenu_path | dmenu ${1+"$@"}` && exec $exe

Before updating to a newer version of dmenu (where this is included), I had written my own dmenu_run script. Although I wrote it, I actually don't understand how this one worked either. It was a trial and error thing, and when I try to think it through I always conclude that it shouldn't work.

#!/bin/bash
IFS="\t"   # (was actually a literal tab character in my script)
`dmenu_path | dmenu $*`

This does not work without redefining $IFS, so I figured that dwm is not somehow making sure that spaces are interpretted correctly. But by stopping spaces from separating arguments, shouldn't this cause huge problems for everything except the font name?

An example of how this would be called by dwm:

dmenu_run -fn -*-dejavu sans-medium-r-normal-*-12-*-*-*-*-*-*-*

(Note the space in the font name)

So what is going on here? I realize that my question is somewhat confusing. I'm happy to clarify anything that is confusing - I found it very hard to clearly ask this question.

Last edited by fflarex (2008-11-07 05:06:24)

Offline

#2 2008-11-07 07:20:21

Aprz
Member
From: Newark
Registered: 2008-05-28
Posts: 277

Re: why does this work? (dmenu_run shell script...)

dmenu_run -fn -*-dejavu sans-medium-r-normal-*-12-*-*-*-*-*-*-*

Shouldn't work and it doesn't work for me. You need quotes around the font.

dmenu_run -fn '-*-dejavu sans-medium-r-normal-*-12-*-*-*-*-*-*-*'

Like that.

Last edited by Aprz (2008-11-07 07:34:19)

Offline

#3 2008-11-07 13:51:21

fflarex
Member
Registered: 2007-09-15
Posts: 466

Re: why does this work? (dmenu_run shell script...)

Then how does dwm call it? This isn't being typed into a prompt but rather it happens with a keyboard shortcut in dwm. But when I wrote my own version of the script, it didn't work until I took measures to accomodate that space.

EDIT: Here's the line from config.h, so you don't have to go look at your source:

static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };

Last edited by fflarex (2008-11-07 13:56:23)

Offline

#4 2008-11-07 14:26:35

skymt
Member
Registered: 2006-11-27
Posts: 443

Re: why does this work? (dmenu_run shell script...)

First off, sorry for all the shell-speak. This is a bit of an edge case, so it's sort of unavoidable. That said, I'll summarize what you need to know at the end.

The dwm version of the script uses $@ in double quotes. @ contains all the parameters passed to the shell, just like * does. The main useful difference is a special case: when double-quoted, $@ expands to the list of arguments, each as a single shell word. Double-quoted $* expands to the list of arguments as a single word delimited by $IFS. (Both variables expand to the list of arguments [with word splitting applied according to $IFS, hence your spaces problem] when unquoted.) Here's the logic flow:

1. dwm calls dmenu_run with the list of arguments specified in your config.h. It calls it directly, not running a command through a shell, so word splitting is never performed and spaces in values don't matter.
2. dmenu_run calls dmenu with the list of arguments it was given. It uses two shell tricks: first, quoted-@ to pass the list of arguments without word splitting. Second, the ${foo+bar} expansion syntax, which expands to bar if foo is defined, otherwise the null string (""). So it expands to the full list of arguments, each as a single word, only if arguments were passed (if $1 is defined).


What you need to know: You almost always want to use '"$@"'. Unless you want all your arguments as a single string, in which case you want '"$*"'. Other forms are practically useless.

Last edited by skymt (2008-11-07 14:26:58)

Offline

#5 2008-11-07 16:00:19

fflarex
Member
Registered: 2007-09-15
Posts: 466

Re: why does this work? (dmenu_run shell script...)

Thank you! The shell-speak is actually what I was looking for. I knew about $@, but had never run into a situation where $* didn't work fine in my scripts. Mostly I was confused by the ${foo+bar} syntax, which I will have to look into a little more.

So just to clarify: dwm made sure the space was used correctly, but then my use of $* instead of "$@" messed that up?

Offline

#6 2008-11-07 16:22:21

skymt
Member
Registered: 2006-11-27
Posts: 443

Re: why does this work? (dmenu_run shell script...)

fflarex wrote:

So just to clarify: dwm made sure the space was used correctly, but then my use of $* instead of "$@" messed that up?

Well, to be more precise, dwm doesn't actually care about spaces. When dwm calls dmenu_run, it calls execvp() with the array of arguments you specified in that line from config.h. It never touches a shell until the script starts, so the bash instance running the script gets the arguments exactly as they were written in the array, without any word splitting or even the need to work around it.

But yeah, pretty much.

Last edited by skymt (2008-11-07 16:22:51)

Offline

Board footer

Powered by FluxBB