bash:在同一命令中分配变量并打印到标准输出

bash:在同一命令中分配变量并打印到标准输出

我正在编写一个 bash 脚本,该脚本读取包含字段和字段值的 csv 文件,并从输入中创建一个 json 字符串。

为简单起见,我有一个 bash 脚本,它接受两个模拟上述脚本的参数。

#!/bin/bash

fieldValue1=$1
fieldValue2=$2

jsonString='{"field1":"'$fieldValue1'", "field2":"'$fieldValue2'"}'
echo $jsonString

当我使用两个参数调用上面的脚本时,我正确地得到以下输出:

 ./test.sh "abc" "def"
{"field1":"abc", "field2":"def"}

我现在想要实现的目标是能够在第一个参数中分配和打印变量,然后在第二个参数中重用第一个参数中的变量。

例如,当我使用以下示例参数调用脚本时(语法很灵活):

 ./test.sh "VAR=abc;echo $VAR" "$VAR"

那么输出应该是这样的:

{"field1":"abc", "field2":"abc"}

其实际用途是,例如对于大型输入文件中的真实脚本,我只需维护一次日期:

startDate1,field2,startDate2
var startDate=1/1/2020;echo $startDate,someValue,$startDate
2/1/2020,someOtherValue,$startDate

有人知道如何最好地实现上述输出吗?

答案1

为什么不var=abc; ./test.sh "$var" "$var"

或者,使用一个参数调用脚本,脚本将处理缺失的值:

#!/bin/bash
fieldValue1=$1
fieldValue2=${2:-$1}
...

然后:./test.sh foo输出{"field1"="foo", "field2"="foo"}


请注意,这不是 JSON:使用冒号不等于:{"field1":"foo", "field2":"foo"}

此外,当您分配 jsonString 变量时,您将不加引号的变量。做这个

jsonString='{"field1":"'"$fieldValue1"'", "field2":"'"$fieldValue2"'"}'
# ......................^............^...............^............^
# or
jsonString="{'field1':'$fieldValue1', 'field2':'$fieldValue2'}"
# or
printf -v jsonString '{"field1":"%s","field2":"%s"}' "$fieldValue1" "$fieldValue2"

此外,您还应该防止使用包含引号字符的值:

printf -v jsonString '{"field1":"%s","field2":"%s"}' \
    "${fieldValue1//\"/\\\"}" \
    "${fieldValue2//\"/\\\"}"

然后

$ ./test.sh 'he said "foo"'
{"field1":"he said \"foo\"","field2":"he said \"foo\""}

基于更新的要求。分配变量必须是一个单独的步骤。你还缺少$(...) 命令替换句法

首先更新一下脚本:

#!/bin/bash
pairs=()
for ((i=1; i<=$#; i++)); do
    value=${!i}
    pairs+=( "$(printf '"%s":"%s"' "field$i" "${value//\"/\\\"}")" )
done
IFS=,
echo "{${pairs[*]}}"

然后像这样调用它

startDate=1/1/2020
bash test.sh "$startDate" someOtherValue "$startDate" "$(date -u -d "$startDate 1 hour" "+%FT%TZ")" "anotherValue"

并得到这个输出:

{"field1":"1/1/2020","field2":"someOtherValue","field3":"1/1/2020","field4":"2020-01-01T01:00:00Z","field5":"anotherValue"}

答案2

看起来好像你正试图重新csvjson发明CSV套件:

$ cat file.csv
A,B,C
1,2,3
4,5,6

$ csvjson file.csv
[{"A": 1.0, "B": 2.0, "C": 3.0}, {"A": 4.0, "B": 5.0, "C": 6.0}]

$ csvjson -i 4 file.csv
[
    {
        "A": 1.0,
        "B": 2.0,
        "C": 3.0
    },
    {
        "A": 4.0,
        "B": 5.0,
        "C": 6.0
    }
]

答案3

如果将第一个参数括在 中$(),您将获得所需的输出。

./test.sh "$(VAR=abc; echo $VAR)" "def"

在这种情况下,bash将使用子shell来执行设置VAR=abc,然后执行echo $VAR,然后该子shell中的STDOUT将被用作test.sh参数$1


编辑

要从变量的单个设置中获取分配的两个变量,您需要从子 shell 中获取这两个变量。

./test.sh $(VAR='abc'; echo $VAR $VAR)

通过删除引号$(),我们知道捕获子 shell 的 STDOUT 中的第一个单词 as$1和第二个单词 as $2

但是,由于$VAR未在父 shell 中设置,因此无法$VAR直接使用。

但是,您可以使用子 shell 来设置$VAR.

VAR=$(VAR=abc; echo $VAR) ./test.sh $VAR $VAR

或者,为了可读性

VAR=$(FOO=abc; echo $FOO) ./test.sh $VAR $VAR

相关内容