我有一个外部程序,可以通过stdin($ 1)将大量信息交给我的脚本。
我得到如下一行:
session number="2018/06/20-234",data name="XTRDF_SLSLWX3_FSLO",data group="Testing",status="Error",data type="0"
现在我要使用此行拆分为单个变量。
到目前为止,我考虑了两种方法:
INPUT='session number="2018/06/20-234",data name="XTRDF_SLSLWX3_FSLO",data group="Testing",status="Error",data type="0"'
echo "$INPUT" | tr ',' '\n' | tr ' ' '_' > vars.tmp
set vars.tmp
这将一直执行到我有一个空格的data_name变量,我的trim命令会自动将其更改为_,并且在以后的检查中我分配的变量不再正确。
所以我考虑将输入加载到数组中,并对数组进行一些模式替换以删除所有内容,直到并包括=为止,然后再进行一些变量赋值
INPUT='session number="2018/06/20-234",data name="XTRDF_SLSLWX3_FSLO",data group="Testing",status="Error",data type="0"'
IFS=',' read -r -a array <<< "$INPUT"
array=("${array[@]/#*=/}")
session_number="${array[0]}"
data_name="${array[1]}"
....
但是,如果数据名称或数据组中某处有=,那么现在我有一个奇怪的行为会切断输入,并且我不知道这是否是这样做的方法。我敢肯定,与空格相比,数据名称或数据组字段中不应包含=,但您永远不会知道...
我该怎么办?
答案 0 :(得分:1)
如果您不必担心引用数据中的逗号或文字引号,则以下内容可以处理您所问的情况(数据中的杂散=
):
#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Requires bash 4.0 or newer" >&2; exit 1;; esac
input='session number="2018/06/20-234",data name="XTRDF_SLSLWX3_FSLO",data group="Testing",status="Error",data type="0"'
declare -A data=( )
IFS=, read -r -a pieces <<<"$input"
for piece in "${pieces[@]}"; do
key=${piece%%=*} # delete everything past the *first* "=", ignoring later ones
value=${piece#*=} # delete everything before the *first* "=", ignoring later ones
value=${value#'"'} # remove leading quote
value=${value%'"'} # remove trailing quote
data[$key]=$value
done
declare -p data
...结果(添加空格以提高可读性,否则输出文字):
declare -A data=(
["data type"]="0"
[status]="Error"
["data group"]="Testing"
["data name"]="XTRDF_SLSLWX3_FSLO"
["session number"]="2018/06/20-234"
)
现在,假设您要做需要担心引号内的逗号!考虑以下输入:
input='session number="123",error="Unknown, please try again"'
现在,如果我们尝试在不考虑逗号位置的情况下分割逗号,我们将使用error="Unknown
和please try again
作为杂散值。
要解决此问题,我们可以将GNU awk与FPAT功能一起使用。
#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Requires bash 4.0 or newer" >&2; exit 1;; esac
input='session number="123",error="Unknown, please try again"'
# Why do so many awk people try to write one-liners? Isn't this more readable?
awk_script='
BEGIN {
FPAT = "[^=,]+=(([^,]+)|(\"[^\"]+\"))"
}
{
printf("%s\0", NF)
for (i = 1; i <= NF; i++) {
printf("%s\0", $i)
}
}
'
while :; do
IFS= read -r -d '' num_fields || break
declare -A data=( )
for ((i=0; i<num_fields; i++)); do
IFS= read -r -d '' piece || break
key=${piece%%=*}
value=${piece#*=}
value=${value#'"'}
value=${value%'"'}
data[$key]=$value
done
declare -p data # maybe invoke a callback here, before going on to the next line
done < <(gawk "$awk_script" <<<"$input")
...此后输出正确:
declare -A data=(["session number"]="123" [error]="Unknown, please try again" )