我有一个这样的字符串:
data-target=".navbar0001, .collapse.show"
分隔符zone=INTERNET|status=good|routed=special|location=001|resp=user|switch=not set|stack=no|dswres=no|CIDR=10.10.10.0/24|allowDuplicateHost=disable|inheritAllowDuplicateHost=true|pingBeforeAssign=enable|inheritPingBeforeAssign=true|locationInherited=true|gateway=10.10.10.100|inheritDefaultDomains=true|inheritDefaultView=true|inheritDNSRestrictions=true|name=SCB-INET-A
内的顺序可以是随机的 - 这意味着键值对可以在字符串中随机排序。
我想要一个如下输出字符串:
|
输出中的所有值都是来自
上面的键值字符串的值有没有人知道如何用 awk 或 sed 来解决这个问题?
答案 0 :(得分:1)
鉴于您的输入是变量var:
var="zone=INTERNET|status=good|routed=special|location=001|resp=user|switch=not set|stack=no|dswres=no|CIDR=10.10.10.0/24|allowDuplicateHost=disable|inheritAllowDuplicateHost=true|pingBeforeAssign=enable|inheritPingBeforeAssign=true|locationInherited=true|gateway=10.10.10.100|inheritDefaultDomains=true|inheritDefaultView=true|inheritDNSRestrictions=true|name=SCB-INET-A"
echo "$var" | tr "|" "\n" | sed -n -r "s/(zone|name|gateway)=(.*)/\"\2\"/p"
"INTERNET"
"10.10.10.100"
"SCB-INET-A"
使用另外两个管道插入逗号并删除换行符:
SOFAR | tr "\n" "," | sed 's/,$//'
"INTERNET","10.10.10.100","SCB-INET-A"
答案 1 :(得分:1)
每当你有名字时 - >输入中的值对最好的方法是创建这些映射的数组(下面是f[]
),然后按名称访问这些值:
$ cat tst.awk
BEGIN { RS="|"; FS="[=\n]"; OFS="," }
{ f[$1] = "\"" $2 "\"" }
END { print f["zone"], f["CIDR"], f["name"] }
$ awk -f tst.awk file
"INTERNET","10.10.10.0/24","SCB-INET-A"
以上将有效地工作(即比shell循环快几个数量级)并且在任何UNIX机器上的任何shell中都可以使用任何awk,这与目前为止所有依赖于非POSIX功能的其他答案不同。它执行完整的字符串匹配而不是部分正则表达式匹配,就像其他一些答案一样,因此它非常强大,并且在给定部分匹配时不会导致输出错误。它也不会解释任何输入字符(例如转义序列和/或globbing字符),就像你的其他一些答案那样,而只是在输出中按原样强健地再现它们。
如果您需要增强它以打印任何额外的字段值,只需将它们作为, f["<field name>"]
添加到print语句中,如果您需要更改输出格式或执行任何其他操作,那么它们也绝对是微不足道的
答案 2 :(得分:0)
使用awk
:
var="zone=INTERNET|status=good|routed=special|location=001|resp=user|switch=not set|stack=no|dswres=no|CIDR=10.10.10.0/24|allowDuplicateHost=disable|inheritAllowDuplicateHost=true|pingBeforeAssign=enable|inheritPingBeforeAssign=true|locationInherited=true|gateway=10.10.10.100|inheritDefaultDomains=true|inheritDefaultView=true|name=SCB-INET-A|inheritDNSRestrictions=true"
awk -v RS='|' -v ORS=',' -F= '$1~/zone|gateway|name/{print "\"" $2 "\""}' <<<"$var" | sed 's/,$//'
"INTERNET","10.10.10.100","SCB-INET-A"
输入记录分隔符RS
设置为|
。
输入字段分隔符FS
设置为=
。
输出记录分隔符ORS
设置为,
。
$1~/zone|gateway|name/
正在过滤要提取的参数。 print
语句被添加到参数值的双引号中。
sed
语句是删除烦人的上一个,
(print
语句正在添加)。
答案 3 :(得分:0)
不使用sed
或awk
,而是使用Bash Arrays功能。
line="zone=INTERNET|sta=good|CIDR=10.10.10.0/24|a=1 1|...=...|name=SCB-INET-A"
echo "$line" | tr '|' '\n' | {
declare -A vars
while read -r item ; do
if [ -n "$item" ] ; then
vars["${item%%=*}"]="${item##*=}"
fi
done
echo "\"${vars[zone]}\",\"${vars[CIDR]}\",\"${vars[name]}\"" ; }
此方法的一个优点是,您始终可以按顺序获取字段,而与输入行中的字段顺序无关。
答案 4 :(得分:0)
使用Bash的另一个解决方案。不是最短的,但我希望它是最好的可读性,所以最好的可维护性。
#!/bin/bash
# Function split_key_val()
# selects values from a string with key-value pairs
# IN: string_with_key_value_pairs wanted_key_1 [wanted_key_2] ...
# OUT: result
function split_key_val {
local KEY_VAL_STRING="$1"
local RESULT
# read the string with key-value pairs into array
IFS=\| read -r -a ARRAY <<< "$KEY_VAL_STRING"
#
shift
# while there are wanted-keys ...
while [[ -n $1 ]]
do
WANTED_KEY="$1"
# Search the array for the wanted-key
for KEY_VALUE in "${ARRAY[@]}"
do
# the key is the part before "="
KEY=$(echo "$KEY_VALUE" |cut --delimiter="=" --fields=1)
# the value is the part after "="
VALUE=$(echo "$KEY_VALUE" |cut --delimiter="=" --fields=2)
if [[ $KEY == $WANTED_KEY ]]
then
# if result is empty; result= found value...
if [[ -z $RESULT ]]
then
# (quote the damned quotes)
RESULT="\"${VALUE}\""
else
# ... else add a comma as a separator
RESULT="${RESULT},\"${VALUE}\""
fi
fi # key == wanted-key
done # searched whole array
shift # prepare for next wanted-key
done
echo "$RESULT"
return 0
}
STRING="zone=INTERNET|status=good|routed=special|location=001|resp=user|switch=not set|stack=no|dswres=no|CIDR=10.10.10.0/24|allowDuplicateHost=disable|inheritAllowDuplicateHost=true|pingBeforeAssign=enable|inheritPingBeforeAssign=true|locationInherited=true|gateway=10.10.10.100|inheritDefaultDomains=true|inheritDefaultView=true|inheritDNSRestrictions=true|name=SCB-INET-A"
split_key_val "$STRING" zone CIDR name
结果是: “互联网”, “10.10.10.0/24”, “SCB-INET-A”
答案 5 :(得分:0)
不使用更复杂的文本编辑工具(作为练习!)
$ tr '|' '\n' <file | # make it columnar
egrep '^(zone|CIDR|name)=' | # get exact key matches
cut -d= -f2 | # get values
while read line; do echo '"'$line'"'; done | # quote values
paste -sd, # flatten with comma
将给出
"INTERNET","10.10.10.0/24","SCB-INET-A"
您也可以将while
语句替换为xargs printf '"%s"\n'