使用空格拆分/ proc / cmdline参数

时间:2009-06-14 18:38:23

标签: parsing shell word argument-passing split

解析/ proc / cmdline的大多数脚本将其分解为单词,然后使用case语句过滤掉参数,例如:

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

问题是当WLAN ESSID有空格时。用户希望设置wlan='FOO BAR'(就像一个shell变量)然后使用上面的代码获得'FOO的意外结果,因为for循环在空格上分割。

有没有更好的方法从shell脚本解析/proc/cmdline,几乎无法评估它?

还是有一些引用技巧?我以为我可能会要求用户实体引用空格并像这样解码:/bin/busybox httpd -d "FOO%20BAR"。或者这是一个糟糕的解决方案?

9 个答案:

答案 0 :(得分:20)

有一些方法:

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

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

  3. 这些适用于大多数情况,但是当参数中包含空格时会失败。但是我确实认为有比使用/proc/PID/cmdline更好的方法。

答案 1 :(得分:9)

set -- $(cat /proc/cmdline)
for x in "$@"; do
    case "$x" in
        wlan=*)
        echo "${x#wlan=}"
        ;;
    esac
done

答案 2 :(得分:3)

最常见的是,当空格不可接受时,会使用\0ctal转义序列。

在Bash中,printf可用于取消它们,例如

CMDLINE='quiet union=aufs wlan=FOO\040BAR'
for x in $CMDLINE; do
    [[ $x = wlan=* ]] || continue
   printf '%b\n' "${x#wlan=}"
done

答案 3 :(得分:2)

使用xagrs -n1

[centos@centos7 ~]$ CMDLINE="quiet union=aufs wlan='FOO BAR'"
[centos@centos7 ~]$ echo $CMDLINE
quiet union=aufs wlan='FOO BAR'
[centos@centos7 ~]$ echo $CMDLINE | xargs -n1
quiet
union=aufs
wlan=FOO BAR

答案 4 :(得分:1)

您可以使用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

然后你就像在普通的shell中一样引用和/或转义事物。

答案 5 :(得分:1)

由于您希望shell解析/ proc / cmdline内容,因此很难避免使用它进行评估。

[ { "namespace": "com.mycode.avro"
  , "type": "record"
  , "name": "NestedObject"
  , "fields":
    [ { "name": "timestamp", "type": "long", "doc": "Instant in time (milliseconds since epoch)." }
    , { "name": "objs", "type": { "type": "array", "items": "DeeplyNestedObject" }, "doc": "Elided." }
    ]
  }
]

这显然是危险的,因为它会盲目地运行内核命令行中指定的任何内容,如#!/bin/bash eval "kernel_args=( $(cat /proc/cmdline) )" for arg in "${kernel_args[@]}" ; do case "${arg}" in wlan=*) echo "${arg#wlan=}" ;; esac done

转义空格(\ x20)听起来像是最直接和最安全的方式。

一个重要的选择是使用一些解析器,它可以理解类似shell的语法。 在这种情况下,您甚至可能不再需要shell。 例如,使用python:

quiet union=aufs wlan=FOO ) ; touch EVIL ; q=( q

答案 6 :(得分:0)

在豪华中:

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

您可以定义一个函数并将$ CMDLINE 不带引号的作为函数的参数。然后你将调用shell的解析机制。请注意,您应该在它将使用的shell上测试它 - zsh使用引号做一些有趣的事情; - )。

然后你可以告诉用户像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

(豪华 - 符合政策的普通SHell,一个剥夺了标准POSIX以外任何功能的shell)

答案 7 :(得分:-1)

发现here是一个很好的方法来使用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

答案 8 :(得分:-3)

使用shell脚本中的/ proc / cmdline来访问命令行是错误的方法。为什么不使用$ @?

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

编辑:在$ @附近添加引号。

编辑:误读了这个问题; / proc / cmdline是内核命令行。