Skip to content

Commit

Permalink
Enhance @sh to output objects as bash associative array initialisers
Browse files Browse the repository at this point in the history
Bash allows associative arrays to be initialised using declarations of
the form

  name=([foo]=1 [bar]=42 [baz]="hello")

At present, the @sh filter can format arrays into space-separated
strings:

$ ip -j addr | jq -c -r '.[] | {ifname, addr_info: .addr_info[]} | {ifname, family: .addr_info["family"], address: .addr_info["local"]} | [.[]] | @sh' | head -n 3
'lo' 'inet' '127.0.0.1'
'lo' 'inet6' '::1'
'eth0' 'inet' '93.93.131.233'

We alter the @sh filter to output objects as well, in a
format suitable for use as bash associative array initialisers:

$ ip -j addr | jq -c -r '.[] | {ifname, addr_info: .addr_info[]} | {ifname, family: .addr_info["family"], address: .addr_info["local"]} | @sh' | head -n 3
[ifname]='lo' [family]='inet' [address]='127.0.0.1'
[ifname]='lo' [family]='inet6' [address]='::1'
[ifname]='eth0' [family]='inet' [address]='93.93.131.233'

Allowing us to use symbolic names to reference values:

$ ip -j addr | jq -c -r '.[] | {ifname, addr_info: .addr_info[]} | {ifname, family: .addr_info["family"], address: .addr_info["local"]} | @sh' | while read initialiser; do declare -A iface; eval iface=($initialiser); echo "Interface ${iface[ifname]} has ${iface[family]} address ${iface[address]}"; done | head -n 3
Interface lo has inet address 127.0.0.1
Interface lo has inet6 address ::1
Interface eth0 has inet address 93.93.131.233
  • Loading branch information
Bob Ham committed Jan 14, 2021
1 parent 80052e5 commit 264bd1f
Showing 1 changed file with 55 additions and 23 deletions.
78 changes: 55 additions & 23 deletions src/builtin.c
Expand Up @@ -529,6 +529,36 @@ static jv escape_string(jv input, const char* escapings) {

}

static jv shell_format(jv input) {
switch (jv_get_kind(input)) {
case JV_KIND_NULL:
case JV_KIND_TRUE:
case JV_KIND_FALSE:
case JV_KIND_NUMBER:
return jv_dump_string(input, 0);

case JV_KIND_STRING: {
jv escaped = jv_string("'");
escaped = jv_string_concat(escaped, escape_string(input, "''\\''\0"));
return jv_string_append_str(escaped, "'");
}

default:
return type_error(input, "can not be escaped for shell");
}
}

static void shell_line_format(jv *line, jv input) {
jv str = shell_format(input);

if (jv_is_valid(str)) {
*line = jv_string_concat(*line, str);
} else {
jv_free(*line);
*line = str;
}
}

static jv f_format(jq_state *jq, jv input, jv fmt) {
if (jv_get_kind(fmt) != JV_KIND_STRING) {
jv_free(input);
Expand Down Expand Up @@ -619,33 +649,35 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
return line;
} else if (!strcmp(fmt_s, "sh")) {
jv_free(fmt);
if (jv_get_kind(input) != JV_KIND_ARRAY)
input = jv_array_set(jv_array(), 0, input);
jv line = jv_string("");
jv_array_foreach(input, i, x) {
if (i) line = jv_string_append_str(line, " ");
switch (jv_get_kind(x)) {
case JV_KIND_NULL:
case JV_KIND_TRUE:
case JV_KIND_FALSE:
case JV_KIND_NUMBER:
line = jv_string_concat(line, jv_dump_string(x, 0));
break;

case JV_KIND_STRING: {
line = jv_string_append_str(line, "'");
line = jv_string_concat(line, escape_string(x, "''\\''\0"));
line = jv_string_append_str(line, "'");
break;
jv_kind input_kind = jv_get_kind(input);
if (input_kind == JV_KIND_ARRAY) {
jv_array_foreach(input, i, x) {
if (i) line = jv_string_append_str(line, " ");
shell_line_format(&line, x);
if (!jv_is_valid(line)) {
break;
}
}

default:
jv_free(input);
jv_free(line);
return type_error(x, "can not be escaped for shell");
} else if (input_kind == JV_KIND_OBJECT) {
jv_object_foreach(input, key, x) {
if (jv_string_length_bytes(jv_copy(line)) > 0) {
line = jv_string_append_str(line, " ");
}
line = jv_string_append_str(line, "[");
line = jv_string_concat(line, key);
line = jv_string_append_str(line, "]=");
shell_line_format(&line, x);
if (!jv_is_valid(line)) {
break;
}
}
} else {
shell_line_format(&line, input);
}
if (jv_is_valid(line)) {
jv_free(input);
}
jv_free(input);
return line;
} else if (!strcmp(fmt_s, "base64")) {
jv_free(fmt);
Expand Down

0 comments on commit 264bd1f

Please sign in to comment.