jo를 사용하여 쉘의 연관 배열에서 JSON 객체를 만드는 방법은 무엇입니까?

jo를 사용하여 쉘의 연관 배열에서 JSON 객체를 만드는 방법은 무엇입니까?

나는 대해 알고있다연관 배열에서 JSON을 생성하는 방법하지만 그건 내 문제가 아닙니다.

다음과 같은 연관 배열이 있습니다.

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

이제 이 연관 배열을 다음 JSON으로 변환해야 합니다.

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "Index": ["components/Index/Exports"],
            "Shared": ["components/Shared/Exports"],
            "Icons": ["components/Icons/Exports"],
        }
    }
}

jo및 을 사용하고 싶습니다 jq. 하지만 중첩을 알 수 없습니다.

나는 이 코드를 시도했다:

jo -p compilerOptions[baseUrl]=. compilerOptions[paths]="$(jo -p a ${Aliases[@]})"

하지만 실행조차 되지 않습니다.

답변1

가능한 해결책 중 하나는 다음과 같습니다.

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

jq -n --argjson n "${#aliases[@]}" '
        { compileroption: {
                baseurl: ".",
                paths:
                (
                        reduce range($n) as $i ({};
                                .[$ARGS.positional[$i]] = [$ARGS.positional[$i+$n]]
                        )
                )
        } }' --args "${!aliases[@]}" "${aliases[@]}"

jo연관 배열을 사용하는 대신 키와 값은 명령 끝에 위치 인수 aliases로 전달됩니다( 사용되는 경우 항상 마지막 옵션이어야 함). 유틸리티 는 키와 값을 단일 배열로 받습니다 . 즉, 배열의 첫 번째 절반에는 키가 포함되고 배열의 두 번째 절반에는 해당 값이 포함됩니다.jq--args--argsjq$ARGS.positional

표현식의 본문은 jq출력 객체를 생성하고 reduce0부터 시작하는 정수 범위에서 작동합니다. 여기서 는 배열의 요소 수입니다. 이 작업은 :th 매개변수를 키로 사용하고 + :th 매개변수를 해당 배열 값의 요소로 사용하여 위치 매개변수를 하나씩 추가하여 객체를 만듭니다.$n$naliasesreducepaths$i$i$n


jo연관 배열의 각 키-값 쌍에 대한 리프 객체를 생성하는 방법은 약간 다릅니다.

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

for key in "${!aliases[@]}"; do
        jo "$key[]=${aliases[$key]}"
done

그러면 세 개의 개체가 출력됩니다.

{"Icons":["components/Icons/Exports"]}
{"Index":["components/Index/Exports"]}
{"Shared":["components/Shared/Exports"]}

우리는 이것을 이런 식으로 사용하고 있기 때문에 jo배열의 키에 몇 가지 명백한 제한을 적용합니다( =등을 포함하지 않을 수 있음 []).

우리는 이것을 다음 jq과 같이 사용할 수 있습니다 jo:

for key in "${!aliases[@]}"; do
        jq -n --arg key "$key" --arg value "${aliases[$key]}" '.[$key] = [$value]'
done

그런 다음 이를 읽고 생성 중인 객체의 올바른 위치에 추가할 수 있습니다 jq.

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

for key in "${!aliases[@]}"; do
        jo "$key[]=${aliases[$key]}"
done |
jq -n '{ compileroptions: {
        baseURL: ".",
        paths: (reduce inputs as $item ({}; . += $item)) } }'

여기서 가장 큰 차이점은 jq콘텐츠를 명령줄 옵션으로 전달하지 않고 JSON 개체 스트림으로 전달한다는 것입니다.

답변2

perl개인적으로 저는 쉘(특히 bash!) 대신 다른 적절한 프로그래밍 언어를 사용하겠습니다 . 아니면 최소한 zsh더 나은 연관 배열 지원 으로 전환하여 perlJSONy 작업을 수행하는 데 사용하세요.

#! /usr/bin/perl
use JSON;

%my_aliases = (qw(
  Index   components/Index/Exports
  Shared  components/Shared/Exports
  Icons   components/Icons/Exports
));

$j->{compilerOptions}->{baseUrl} = "";
$j->{compilerOptions}->{paths}->{$_} = [$my_aliases{$_}] for keys%my_aliases;
print to_json($j, {"pretty" => 1});

또는:

#! /bin/zsh -

typeset -A my_aliases=(
  Index   components/Index/Exports
  Shared  components/Shared/Exports
  Icons   components/Icons/Exports
)

print -rNC1 -- "${(kv@)my_aliases}" |
  perl -MJSON -0e '
    chomp (@records = <>);
    %my_aliases = @records;
    $j->{compilerOptions}->{baseUrl} = "";
    $j->{compilerOptions}->{paths}->{$_} = [$my_aliases{$_}] for keys%my_aliases;
    print to_json($j, {"pretty" => 1})'

관련 정보