views:

1123

answers:

3

Most scripts that parse /proc/cmdline break it up into words and then filter out arguments with a case statement, example:

CMDLINE="quiet union=aufs wlan=FOO"
for x in $CMDLINE
do
»···case $x in
»···»···wlan=*)
»···»···echo "${x//wlan=}"
»···»···;;
»···esac
done

The problem is when the WLAN ESSID has spaces. Users expect to set wlan='FOO BAR' (like a shell variable) and then get the unexpected result of 'FOO with the above code, since the for loop splits on spaces.

Is there a better way of parsing the /proc/cmdline from a shell script falling short of almost evaling it?

Or is there some quoting tricks? I was thinking I could perhaps ask users to entity quote spaces and decode like so: /bin/busybox httpd -d "FOO%20BAR". Or is that a bad solution?

+1  A: 

Using /proc/cmdline from a shell-script to access the command line is the wrong way. Why not use $@?

for arg in "$@"; do
    ...
done

EDIT: added quotes around $@.

EDIT: misread the question; /proc/cmdline is the kernel command line.

JesperE
/proc/cmdline is how arguments are set on Linux distros. e.g. http://webconverger.org/boot/
hendry
Remeber to use quotes around $@ or it will be split in the for-loop. Use for arg in "$@"; do...
Johan Soderberg
@hendry: sorry, I misread it as "/proc/PID/cmdline". /proc/cmdline is the command line of the running kernel, and /proc/PID/cmdline is the command line of process PID. I still don't understand why you want to parse the kernel command line. I don't know much about kernel hacking, but it sounds like parsing /proc/cmdline to figure out information about the running kernel is the wrong approach.
JesperE
A: 

In posh:

$ f() { echo $1 - $3 - $2 - $4 
> }
$ a="quiet union=aufs wlan=FOO"
$ f $a
quiet - wlan=FOO - union=aufs -

You can define a function and give your $CMDLINE unquoted as an argument to the function. Then you'll invoke shell's parsing mechanisms. Note, that you should test this on the shell it will be working in -- zsh does some funny things with quoting ;-).

Then you can just tell the user to do quoting like in shell:

#!/bin/posh
CMDLINE="quiet union=aufs wlan=FOO"
f() {
        while test x"$1" != x 
        do      
                case $1 in
                        union=*)        echo ${1##union=}; shift;;
                        *)              shift;; 
                esac    
        done    
}       
f $CMDLINE

(posh - Policy-compliant Ordinary SHell, a shell stripped of any features beyond standard POSIX)

liori
Why `while` over a more readable `case` statement?
hendry
Because you can eat more arguments (with $2, $3... and more shifts). I agree that this not so useful for x=y arguments; more for -x y. But this solution is more versatile and a bit more idiomatic (seeing it very often in shell scripts).
liori
So how would users quote an essid like 'foo bar'?wlan=foo\040bar like the other answer?I honestly think URL encoding "%20" is easier for the average user than shell octal encodings.
hendry
In this case, a shell-like escaping will apply: CMDLINE="quiet wlan='foo bar bar union=of=consumers and-yet-another word' union=aufs". But... now I think that if this is meant also to be kernel parameters, you should be rather using octal. Kernel does not do shell expansion and might be confused seeing above wlan id.
liori
+1  A: 

Most commonly, \0ctal escape sequences are used when spaces are unacceptable.

In Bash, printf can be used to unescape them, e.g.

CMDLINE='quiet union=aufs wlan=FOO\040BAR'
for x in $CMDLINE; do
    [[ $x = wlan=* ]] || continue
   printf '%b\n' "${x#wlan=}"
done
ephemient
I prefer Web style entity quoting.
hendry
Octal escapes are more common (and traditional) in UNIX environments. This is how to add spaces to mount paths in /etc/fstab, for example.
ephemient
Since this a parameter for a "Web product" Webconverger, where other parameters like homepage http://webconverger.org/boot/ will also be URL encoded, I think my initial choice is best.
hendry
Then you have to use some kind of text processing tool: either sed/perl or a good shell like new bash.
liori