使用awk从更大的JSON字符串中提取令牌

时间:2017-08-11 03:17:07

标签: json ruby bash awk grep

我有一个分配给变量的字符串:

#/bin/bash

fullToken='{"type":"APP","token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs"}'

我只需要在没有引号的情况下提取l0ng_Str1ng.of.d1fF3erent_charAct3rs并将其分配给另一个变量。

我知道我可以使用awksedcut,但我无法绕过原始字符串中的特殊字符。

提前致谢!

编辑:我没有醒来我应该指定这是JSON。感谢到目前为止的回复。

EDIT2:我正在使用BSD(macOS)

5 个答案:

答案 0 :(得分:3)

看起来你有一个JSON字符串。请记住,JSON是无序的,因此如果您下次以不同的顺序输入字符串,则大多数sed,awk,cut解决方案将会失败。

使用JSON解析器是最强大的。

您可以将ruby与其JSON解析器库一起使用:

$ echo "$fullToken" | ruby -r json -e 'p JSON.parse($<.read)["token"];'
"l0ng_Str1ng.of.d1fF3erent_charAct3rs"

或者,如果您不想要引用的字符串(这对Bash很有用):

$ echo "$fullToken" | ruby -r json -e 'puts JSON.parse($<.read)["token"];'
l0ng_Str1ng.of.d1fF3erent_charAct3rs

jq

$ echo "$fullToken" | jq '.token'
"l0ng_Str1ng.of.d1fF3erent_charAct3rs"

即使JSON字符串的顺序不同,所有这些解决方案都能正常工作:

$ echo '{"type":"APP","token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs"}' | jq '.token'
"l0ng_Str1ng.of.d1fF3erent_charAct3rs"
$ echo '{"token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs", "type":"APP"}' | jq '.token'
"l0ng_Str1ng.of.d1fF3erent_charAct3rs"

但是知道你应该使用JSON解析器,你也可以在Gnu Grep中使用PCRE看看背后:

$ echo "$fullToken" | grep -oP '(?<="token":)"([^"]*)'

或者在Perl中:

$ echo "$fullToken" | perl -lane 'print $1 if /(?<="token":)"([^"]*)/'

如果字符串的顺序不同,这两种方法也有效。

或者,使用POSIX awk:

$ echo "$fullToken" | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/"token"/){print $(i+1)}}}'

或者,使用POSIX sed,您可以执行以下操作:

$ echo "$fullToken" | sed -E 's/.*"token":"([^"]*).*/\1/'

这些解决方案最强(使用JSON解析器)更脆弱(sed)。但是我在那里的sed解决方案比其他解决方案更好,因为它将支持JSON字符串中的键,值的顺序不同。

Ps:如果你想删除一行中的引号,那对于sed来说这是一个很好的工作:

$ echo '"quoted string"' 
"quoted string"
$ echo '"quoted string"' | sed -E 's/^"(.*)"$/UN\1/'
UNquoted string

答案 1 :(得分:1)

在awk中:

$ awk -v f="$fullToken" '
BEGIN{
    while(match(f,/[^:{},]+:[^:{},]+/)) {  # search key:value pairs
        p=substr(f,RSTART,RLENGTH)         # set pair to p 
        f=substr(f,RSTART+RLENGTH)         # remove p from f
        split(p,a,":")                     # split to get key and value
        for(i in a)                        # remove leadin and trailing "
            gsub(/^"|"$/,"",a[i])
        if(a[1]=="token") {                # if key is token
            print a[2]                     # output value
            exit                           # no need to process further
        }
    }
}'
l0ng_Str1ng.of.d1fF3erent_charAct3rs

l0ng_String不能包含字符:{}

答案 2 :(得分:1)

GNU sed:

fullToken='{"type":"APP","token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs"}'
echo "$fullToken"|sed -r 's/.*"(.*)".*/\1/'

答案 3 :(得分:0)

grep方法将是,

$ grep -oP '[^"]+(?="[^"]+$)' <<< "$fullToken"
l0ng_Str1ng.of.d1fF3erent_charAct3rs

简要说明,

  • [^"]+grep会提取非"模式
  • (?="[^"]+$):提取到最后"
  • 之前的模式

您也可以使用sed方法来执行此操作,

$sed -E 's/.*"([^"]+)"[^"]+$/\1/' <<< "$fullToken"
l0ng_Str1ng.of.d1fF3erent_charAct3rs

答案 4 :(得分:0)

如果字符串的来源是JSON,那么您应该使用特定于JSON的工具。如果没有,那么考虑一下:

使用awk

$ fullToken='{"type":"APP","token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs"}'
$ echo "$fullToken" | awk -F'"' '{print $8}'
l0ng_Str1ng.of.d1fF3erent_charAct3rs

使用剪切

$ echo "$fullToken" | cut -d'"' -f8
l0ng_Str1ng.of.d1fF3erent_charAct3rs

使用sed

$ echo "$fullToken" | sed -E 's/.*"([^"]*)"[^"]*$/\1/'
l0ng_Str1ng.of.d1fF3erent_charAct3rs

使用bash和上面的一个

以上都适用于POSIX shell。如果shell是bash,那么我们可以使用here-string并消除管道。以削减为例:

$ cut -d'"' -f8 <<<"$fullToken"
l0ng_Str1ng.of.d1fF3erent_charAct3rs