bash: atribua variável e imprima para stdout no mesmo comando [closed]

1

Estou trabalhando em um script bash que lê um arquivo csv com campos e valores de campo e cria uma cadeia json fora da entrada.

Para simplificar, eu tenho um script bash que aceita dois argumentos simulando o script acima.

#!/bin/bash

fieldValue1=$1
fieldValue2=$2

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

Quando eu chamo o script acima com dois argumentos, eu obtenho corretamente a saída abaixo:

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

O que eu estou tentando alcançar agora é poder atribuir e imprimir uma variável no primeiro argumento, depois reutilizar a variável do primeiro argumento no segundo argumento.

Por exemplo, quando eu chamo o script com argumentos de amostra abaixo (a sintaxe é flexível):

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

então a saída deve ficar assim:

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

O uso prático disso é que, por exemplo, para o script real dentro do arquivo de entrada grande, eu só preciso manter uma data uma vez:

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

Alguém tem uma ideia de como alcançar a saída acima?

    
por Bernie Lenz 06.09.2018 / 18:47

3 respostas

2

Por que não var=abc; ./test.sh "$var" "$var" ?

Ou, chame seu script com um argumento e o script manipulará o valor ausente:

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

depois: ./test.sh foo outputs {"field1"="foo", "field2"="foo"}

Note que não é JSON: use dois pontos não iguais: {"field1":"foo", "field2":"foo"}

Você também está deixando as variáveis sem aspas quando atribui a variável jsonString. Faça isso

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

Além disso, você deve proteger contra os valores que contêm caracteres de aspas:

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

Então

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

Com base nos requisitos atualizados. Atribuir a variável deve ser uma etapa separada. Você também está sentindo falta da sintaxe de substituição de comando%

Primeiro, um script atualizado:

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

Em seguida, invoque-o assim

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

e obtenha esta saída:

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

Parece que você está tentando reinventar o csvjson do CSVkit :

$ 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
    }
]
    
por 06.09.2018 / 19:08
0

Se você colocar seu primeiro argumento em $() , obterá a saída desejada.

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

Nesse caso, o bash usará uma subshell para executar a configuração VAR=abc , seguida de echo $VAR , e, em seguida, STDOUT dessa subshell será usado como test.sh argument $1 .

EDITAR

Para obter as duas variáveis atribuídas a partir de uma única configuração da variável, você precisará obter ambas do subshell.

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

Ao remover as aspas em torno de $() , sabemos que capturamos a primeira palavra no STDOUT do subshell como $1 , e a segunda palavra como $2 .

No entanto, como $VAR não está sendo definido no shell pai, você não pode usar $VAR diretamente.

Você pode, no entanto, usar o subshell para definir $VAR .

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

ou, por legibilidade

VAR=$(FOO=abc; echo $FOO) ./test.sh $VAR $VAR
    
por 06.09.2018 / 19:04

Tags