![](/img/trans.png)
[英]Extract data from invalid JSON using bash, sed, grep or awk?
[英]Using awk to extract a token from a larger JSON string
我有一個分配給變量的字符串:
#/bin/bash
fullToken='{"type":"APP","token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs"}'
我只需要提取不帶引號的l0ng_Str1ng.of.d1fF3erent_charAct3rs
並將其分配給另一個變量。
我知道我可以使用awk
, sed
或cut
但是我很難避開原始字符串中的特殊字符。
提前致謝!
編輯:我不醒,我應該指定這是JSON。 到目前為止,感謝您的答復。
EDIT2:我正在使用BSD(macOS)
看起來您那里有一個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字符串中的值以不同的順序排列。
附:如果您想刪除一行中的引號,那么對於sed
來說是個好工作:
$ echo '"quoted string"'
"quoted string"
$ echo '"quoted string"' | sed -E 's/^"(.*)"$/UN\1/'
UNquoted string
在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
不能包含字符:{}
。
GNU sed:
fullToken='{"type":"APP","token":"l0ng_Str1ng.of.d1fF3erent_charAct3rs"}'
echo "$fullToken"|sed -r 's/.*"(.*)".*/\1/'
grep
方法應該是
$ grep -oP '[^"]+(?="[^"]+$)' <<< "$fullToken"
l0ng_Str1ng.of.d1fF3erent_charAct3rs
簡要說明,
[^"]+
: grep
將提取非"
模式 (?="[^"]+$)
:提取直到最后一個"
您也可以使用sed
方法來做到這一點,
$sed -E 's/.*"([^"]+)"[^"]+$/\1/' <<< "$fullToken"
l0ng_Str1ng.of.d1fF3erent_charAct3rs
如果字符串的來源是JSON,則應使用特定於JSON的工具。 如果沒有,請考慮:
$ 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
$ echo "$fullToken" | sed -E 's/.*"([^"]*)"[^"]*$/\1/'
l0ng_Str1ng.of.d1fF3erent_charAct3rs
以上所有功能都適用於POSIX shell。 如果外殼是bash,則可以使用here-string並消除管道。 以切割為例:
$ cut -d'"' -f8 <<<"$fullToken"
l0ng_Str1ng.of.d1fF3erent_charAct3rs
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.