我有一个变量“var”,它有如下所示的json文本
var='{ "user": "jack","password": "kilby","install":"False", "deploy":"False", "build":"123","ip":"0.0.0.0" }'
Iam将其写入.txt文件
touch properties.txt
destdir=./properties.txt
if [ -f "$destdir" ]
then
echo "$var" > "$destdir"
fi
然后我必须将所有键值对存储在一个数组中,以便我进一步处理,如下所示
arr=( $(grep -o \"[^\"]*. properties.txt) )
因此双引号内的所有文本都会移到“arr”
但问题是如果键值对如下所示,即如果值为空,那么“arr”将获得“作为一个条目,这不是令人难以理解的。”
{"k1":"","k2":"","k3":""}
在这种情况下,我需要一个空字符串作为“arr”的条目。
我不太了解bash命令。所以感谢任何帮助。 如果使用“jq”库可以实现结果,那么也欢迎这些建议。 谢谢
答案 0 :(得分:1)
考虑:
$ jq -c 'keys[] as $k | ($k, .[$k])' <<< "$var"
"build"
"123"
"deploy"
"False"
"install"
"False"
"ip"
"0.0.0.0"
"password"
"kilby"
"user"
"jack"
然后,您可以使用bash命令readarray
或成语:
while read -r line
do ...
done
有关详细信息,请参阅jq FAQ。
你不能说出你的最终目标是什么,但我怀疑你最好更全面地使用jq来实现它。
答案 1 :(得分:1)
jq
是从shell解析JSON的工具。你可以用其他语言解析JSON(python,php,ruby,GO等),但是如果你走这条路,你也可以用那种语言编写你的整个程序。
所以..来自bash,你使用jq
:
$ jq 'keys[] as $k | "\($k)=\(.[$k])"' <<<"$var"
"build=123"
"deploy=False"
"install=False"
"ip=0.0.0.0"
"password=kilby"
"user=jack"
如果你想在bash 4+中的关联数组中使用这些对,你可以这样做:
$ declare -A a="( $(jq -r 'keys[] as $k | "[\($k)]=\"\(.[$k])\""' <<<"$var" ) )"
$ declare -p a
declare -A a=([build]="123" [install]="False" [ip]="0.0.0.0" [user]="jack" [deploy]="False" [password]="kilby" )
只要变量索引或值中没有换行符,这样就可以正常工作。为了使它处理更复杂的数据,你需要一个更复杂的处理程序。如果存在换行风险,请在您的问题中提及。
答案 2 :(得分:0)
这个答案的解决方案将键值对读入常规数组的连续元素(元素0
接收第一个键,元素{ {1}}关联值,...),如问题中所示;有关创建Bash v4 + 关联数组的解决方案,请参阅ghoti's helpful answer。
<强> TL;博士强>:
1
Bash v3.x等价物:
readarray -t arr < <(grep -o '"[^"]*.' properties.txt | tr -d \")
arr=()
while IFS= read -r val; do
arr+=( "$val" )
done < <(grep -o '"[^"]*.' properties.txt | tr -d \")
:jq
readarray -t arr < <(jq -r 'keys_unsorted[] as $k | $k, .[$k]' properties.txt)
命令是peak's helpful answer的变体:jq
确保按输入顺序枚举键,keys_unsorted
确保输出结果作为原始值而不是JSON编码,在这种情况下意味着双引号被剥离。
Bash v3.x等价物:
-r
首先要做的事情是:如果可行,始终值得使用适当的JSON解析器,例如jq
。
您的方法存在的问题:
arr=()
while IFS= read -r val; do
arr+=( "$val" )
done < <(jq -r 'keys_unsorted[] as $k | "\($k)\n\(.[$k])"' properties.txt)
在输出中包含封闭的grep -o \"[^\"]*.
,然后将数组赋值"
解析为值的一部分< / EM>
通过管道到arr=( ... )
来删除它们很容易解决这个问题,但tr -d \"
语法然后忽略空字符串,所以你会失去空在过程中输入值。
那就是说,你应该一般避免 arr=( $(...) )
,因为它
(a)总是将命令替换arr=( $(...) )
的输出拆分为空格(分词),而不考虑嵌入的引号字符。(b)默认情况下将得到的字对象扩展(通配符)。
避免这两个问题的安全替代方案 - 至少使用面向行的输入 - 是使用{BES v4.0以来可用的$(...)
; readarray
从读取的行中删除尾随的-t
。
在Bash v3.x中,必须使用\n
循环来读取行,因为的构造几乎等同于while
- readarray -t arr
- 也忽略空条目。
答案 3 :(得分:-1)
首先,我将创建一个返回数组内容的函数。
function myvar {
cat << "END"
{ "user": "jack","password": "kilby","install":"False", "deploy":"False", "build":"123","ip":"0.0.0.0" }
END
}
现在我们可以通过在&#39;,&#39;中的行中剪切字符串来解析var,并找到字段。
myvar | tr ',' '\n' | sed 's/.*"\(.*\)".*\(".*"\).*/\1=\2/'
现在我们有了这些,我们可以通过采购来评估结果。在采购之前,我们将使用勾号将其作为文件:<( echo "My output looks like a file")
OP要求一个阵列,但首先我将展示如何制作环境变量。
source <(myvar | tr ',' '\n' | sed 's/.*"\(.*\)".*\(".*"\).*/\1=\2/')
echo "Environment variable build=${build}"
现在我们想在一个关联数组中填充它(注意:仅限bash版本4。)
declare -A arr
source <(myvar | tr ',' '\n' | sed 's/.*"\(.*\)".*\(".*"\).*/arr[\1]=\2/')
# Show that it worked
for key in ${!arr[@]}; do
echo "Array[${key}]=${arr[${key}]}"
done
答案 4 :(得分:-1)
如果不想判断您选择解析该类数据的方法是对还是错,即使我不同意您选择的解析json数据的方法,我也会尝试回答您的问题。
在代码的这一点上,您将创建一个名为arr的数组:
arr=( $(grep -o \"[^\"]*. properties.txt) )
如果你要求bash告诉你这个数组中存储了什么,你会收到回复:
$ declare -p arr
declare -a arr=([0]="\"user\"" [1]="\"jack\"" [2]="\"password\"" [3]="\"kilby\"" \
[4]="\"install\"" [5]="\"False\"" [6]="\"deploy\"" [7]="\"\"" \
[8]="\"build\"" [9]="\"123\"" [10]="\"ip\"" [11]="\"0.0.0.0\"")
请注意我已将var字段"deploy":"false"
修改为"deploy":""
以测试我的答案 - 这是上面的[7]。
我发现处理数组中缺少字段的最简单方法是使用这样的bash替换技术重新定义相同的arr数组:
$ arr=( ${arr[@]//\"\"/\"empty\"/} )
$ declare -p arr
declare -a arr=([0]="\"user\"" [1]="\"jack\"" [2]="\"password\"" [3]="\"kilby\"" \
[4]="\"install\"" [5]="\"False\"" [6]="\"deploy\"" [7]="\"empty\"/" \
[8]="\"build\"" [9]="\"123\"" [10]="\"ip\"" [11]="\"0.0.0.0\"")
请注意,arr [7]已从之前的"empty"
""
实际上,您的代码会在数组中为空字段存储字符串\"\"
,这些字段将由echo打印,如简单""
在我替换之后,声明-p建议arr[7]=\"empty\"
,它将由echo打印为简单"empty"
。当然,您可以通过保持双引号的转义将此文本更改为您喜欢的任何内容
第二个var2={"k1":"","k2":"","k3":""}
$ var2='{"k1":"","k2":"","k3":""}'
$ echo "$var2" >properties.txt
$ cat properties.txt
{"k1":"","k2":"","k3":""}
$ arr=( $(grep -o \"[^\"]*. properties.txt) )
$ declare -p arr
declare -a arr=([0]="\"k1\"" [1]="\"\"" [2]="\"k2\"" [3]="\"\"" [4]="\"k3\"" [5]="\"\"")
$ arr=( ${arr[@]//\"\"/\"empty\"/} )
$ declare -p arr
declare -a arr=([0]="\"k1\"" [1]="\"empty\"/" [2]="\"k2\"" [3]="\"empty\"/" [4]="\"k3\"" [5]="\"empty\"/")
$ echo "${arr[@]}"
"k1" "empty"/ "k2" "empty"/ "k3" "empty"/
注意:
此解决方案仅建议您的代码的下一步。我还没有测试过你的数据操作技术(比如你的grep等)。
答案 5 :(得分:-1)
为快速反应的人提供了很多帮助。我通过以下方法解决了我的问题
makeKeyValueArray (){
# remove colon and commas
IFS=':' read -ra ADDR <<< "$var"
IFS=',' read -ra ADDR2 <<< "${ADDR[@]}"
echo ${ADDR2[@]} > "$destdir"
#remove curly braces
sed 's/[{}]//g' $destdir > temp_ip_prop.txt
mv temp_ip_prop.txt $destdir
#store each item in a array "arr"
cn=0;
for i in `cat $destdir`
do
arr[$cn]=$i;
((cn=cn+1));
done
}
然后在循环中我比较了数组是否包含&#34;&#34;。如果是这样,我只是将该字段作为空白区域。
我正在做的错误是在
arr =($(grep -o \&#34; [^ \&#34;] * .properties.txt))
这是存储每个\&#34;到阵列。