Skip to content

Commit

Permalink
Make @sh work with objects (fix #1947)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicowilliams committed Aug 7, 2023
1 parent a692060 commit ff72c43
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 3 deletions.
18 changes: 16 additions & 2 deletions docs/content/manual/manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2098,8 +2098,14 @@ sections:
* `@sh`:
The input is escaped suitable for use in a command-line
for a POSIX shell. If the input is an array, the output
will be a series of space-separated strings.
for a POSIX shell using `eval`. If the input is an array,
the output will be a series of space-separated strings.
If the input is an object, the output will be a series of
space-separated variable assignments for all the keys in
the object that are valid shell variable names (other keys
will be ignored).
E.g., `eval $(jq -r '@sh' f.json)`
* `@base64`:
Expand Down Expand Up @@ -2135,6 +2141,14 @@ sections:
input: "\"O'Hara's Ale\""
output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""]

- program: '@sh'
input: '["a b", "c d"]'
output: ["\"'a b' 'c d'\""]

- program: '@sh'
input: '{"foo":"a b", "bar":"c d", "x y":"ignored"}'
output: ["\"foo='a b' bar='c d'\""]

- program: '@base64'
input: '"This is a message"'
output: ['"VGhpcyBpcyBhIG1lc3NhZ2U="']
Expand Down
13 changes: 12 additions & 1 deletion jq.1.prebuilt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions src/builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,48 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
}
jv_free(input);
return line;
} else if (!strcmp(fmt_s, "sh") && jv_get_kind(input) == JV_KIND_OBJECT) {
jv_free(fmt);
jv line = jv_string("");
int first = 1;
jv_object_foreach(input, k, x) {
if (strspn(jv_string_value(k),
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789_") != (size_t)jv_string_length_bytes(jv_copy(k)) ||
strspn(jv_string_value(k), "0123456789") != 0) {
/* Not a valid shell variable name; we don't support assignments to array variables */
jv_free(k);
jv_free(x);
continue;
}
if (!first) line = jv_string_append_str(line, " ");
first = 0;
line = jv_string_concat(line, k);
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;
}

default:
jv_free(input);
jv_free(line);
return type_error(x, "can not be escaped for shell");
}
}
jv_free(input);
return line;
} else if (!strcmp(fmt_s, "sh")) {
jv_free(fmt);
if (jv_get_kind(input) != JV_KIND_ARRAY)
Expand Down
8 changes: 8 additions & 0 deletions tests/man.test

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ff72c43

Please sign in to comment.