解析/ 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"
。或者这是一个糟糕的解决方案?
答案 0 :(得分:20)
有一些方法:
cat /proc/PID/cmdline | tr '\000' ' '
cat /proc/PID/cmdline | xargs -0 echo
这些适用于大多数情况,但是当参数中包含空格时会失败。但是我确实认为有比使用/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是内核命令行。