Разделение аргументов / proc / cmdline пробелами - PullRequest
9 голосов
/ 14 июня 2009

Большинство сценариев, которые разбирают / proc / cmdline, разбивают его на слова, а затем отфильтровывают аргументы с помощью оператора case, например:

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

Проблема в том, что ESSID WLAN имеет пробелов . Пользователи ожидают установить wlan='FOO BAR '(как переменная оболочки), а затем получить неожиданный результат 'FOO с приведенным выше кодом, поскольку цикл for разделяется на пробелы.

Есть ли лучший способ синтаксического анализа /proc/cmdline из сценария оболочки, который почти не оценивает его?

Или есть какие-то хитрости при цитировании? Я подумал, что, возможно, я мог бы попросить пользователей ввести в кавычки объекты и расшифровать их так: /bin/busybox httpd -d "FOO%20BAR". Или это плохое решение?

Ответы [ 8 ]

20 голосов
/ 26 мая 2011

Есть несколько способов:

  1. cat /proc/PID/cmdline | tr '\000' ' '

  2. cat /proc/PID/cmdline | xargs -0 echo

Они будут работать в большинстве случаев, но не будут работать, если в аргументах есть пробелы. Однако я думаю, что было бы лучше, чем использовать /proc/PID/cmdline.

10 голосов
/ 22 февраля 2013
set -- $(cat /proc/cmdline)
for x in "$@"; do
    case "$x" in
        wlan=*)
        echo "${x#wlan=}"
        ;;
    esac
done
3 голосов
/ 17 июня 2009

Чаще всего \0ctal escape-последовательности используются, когда пробелы недопустимы.

В Bash printf можно использовать для их удаления, например,

CMDLINE='quiet union=aufs wlan=FOO\040BAR'
for x in $CMDLINE; do
    [[ $x = wlan=* ]] || continue
   printf '%b\n' "${x#wlan=}"
done
1 голос
/ 17 марта 2017

Поскольку вы хотите, чтобы оболочка анализировала содержимое / proc / cmdline, трудно избежать ее оценки.

#!/bin/bash
eval "kernel_args=( $(cat /proc/cmdline) )"
for arg in "${kernel_args[@]}" ; do
    case "${arg}" in
        wlan=*)
            echo "${arg#wlan=}"
            ;;
    esac
done

Это, очевидно, опасно, так как он слепо запускает все, что было указано в командной строке ядра, например quiet union=aufs wlan=FOO ) ; touch EVIL ; q=( q.

Выход из пробелов (\ x20) звучит как самый простой и безопасный способ.

Тяжелой альтернативой является использование некоторого парсера, который понимает синтаксис, похожий на оболочку. В этом случае вам может даже не понадобиться оболочка. Например, с питоном:

$ cat /proc/cmdline
quiet union=aufs wlan='FOO BAR' key="val with space" ) ; touch EVIL ; q=( q
$ python -c 'import shlex; print shlex.split(None)' < /proc/cmdline
['quiet', 'union=aufs', 'wlan=FOO BAR', 'key=val with space', ')', ';', 'touch', 'EVIL', ';', 'q=(', 'q']
1 голос
/ 02 июня 2011

Вы можете сделать что-то вроде следующего, используя bash, который превратит эти аргументы в переменные, такие как $ cmdline_union и $ cmdline_wlan:

bash -c "for i in $(cat /proc/cmdline); do printf \"cmdline_%q\n\" \"\$i\"; done" | grep = > /tmp/cmdline.sh
. /tmp/cmdline.sh

Тогда вы будете цитировать и / или избегать вещей, как в обычной оболочке.

0 голосов
/ 26 апреля 2013

Найдено здесь хороший способ сделать это с помощью awk, к сожалению, он будет работать только с двойными кавычками:

# Replace spaces outside double quotes with newlines
args=`cat /proc/cmdline | tr -d '\n' | awk 'BEGIN {RS="\"";ORS="\"" }{if (NR%2==1){gsub(/ /,"\n",$0);print $0} else {print $0}}'`

IFS='                                                                           
'                                                                               
for line in $args; do                                                           
     key=${line%%=*}                                                            
     value=${line#*=}                                                           

     value=`echo $value | sed -e 's/^"//' -e 's/"$//'`                          

     printf "%20s = %s\n" "$key" "$value"                                       

done
0 голосов
/ 17 июня 2009

В шикарном:

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

Вы можете определить функцию и указать свой $ CMDLINE без кавычек в качестве аргумента функции. Затем вы будете вызывать механизмы синтаксического анализа оболочки. Обратите внимание, что вы должны проверить это на оболочке, в которой он будет работать - zsh делает некоторые забавные вещи с цитированием; -).

Тогда вы можете просто сказать пользователю делать кавычки, как в оболочке:

#!/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

(шикарный - совместимый с политикой обычный оболочка, оболочка, лишенная любых функций, выходящих за рамки стандартного POSIX)

0 голосов
/ 14 июня 2009

Использование / proc / cmdline из shell-скрипта для доступа к командной строке - неправильный путь. Почему бы не использовать $ @?

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

РЕДАКТИРОВАТЬ: добавлены кавычки около $ @.

РЕДАКТИРОВАТЬ: неправильно прочитать вопрос; / proc / cmdline - это командная строка kernel .

...