I work with a variety of diagnostic files (text / jq
for JSON / yq
for YAML / xpath
for XML, lnav
for log files) in Bash where I need to dynamically determine meaningful data parsing before reporting the final command and its output.
A bit ago as written-up here after I found out via Echoing the last command run in Bash? that I could use !!
to run the previous command and stash its results to a file.
The problem I've encountered is an edge-case that when the ran command uses double-quotes they get omitted when stashed:
$ echo "hello"
hello
$ echo "!!" >> test && !! >> test
echo "echo "hello"" >> test && echo "hello" >> test
$ cat test
echo hello # no double-quotes
hello # but right answer
I've attempted but failed so far to compensate for this via
-e
to have echo
character-escape for yoused
printf
with %b
or %s
tee
""
instead of "
on inner double-quotesscript
The one that's worked best is script
, except A) I only need to retain <5% of commands/output ran & B) I haven't figured out to load my Dotfiles (though I assume that answer lies in man script
's SCRIPT
or SHELL
environment variables which I'd investigate further if that's the best bet).
My problem specifically becomes non-cosmetic and interruptive when asking others to repeat queries I've compiled (for example, to monitor resolution steps effectiveness):
# what I would run
$ echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")'
a-a
# how I would cache for others to run
$ echo "!!" >> test && !! >> test
echo "echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")'" >> test && echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")' >> test
# this command does not work unless !! is within double quotes which partially seems to induce the issue
# what stored to file for others to run
$ cat test
echo '[a-a,b-a]' | jq -rc '.[]|select(.==a-a)'
a-a
# command will error for others because double-quotes dropped
$ echo '[a-a,b-a]' | jq -rc '.[]|select(.==a-a)'
jq: error: a/0 is not defined at <top-level>, line 1:
.[]|select(.==a-a)
jq: error: a/0 is not defined at <top-level>, line 1:
.[]|select(.==a-a)
jq: 2 compile errors
What I expect / hope is
echo
or printf
that character-escapes the double-quotes when running "!!"
or avoids !!
needing the double-quotesscript
(with Dotfiles) to just "run and stash the very last command" (instead of reporting everything and then after manually deleting most of the session)What I'm not interested in (since I work across Operating Systems and can't guarantee other's installations/environments)
ipython
would answer very close to my request, my folks aren't guaranteed to have Python installed so it's a no-go."!!"
without it dropping double-quotes. That works in a lot of places (and I do it though annoyed) but single-quote-escaping causes issues using Salesforce's CLI.I reviewed Stack Overflow's recommended questions but did not think they answered:
!!
by itself does not swallow any quotes. It happens when the shell is interpreting the substitute literally, which includes resolving quoted content. "!!"
doesn't do more than wrapping double quotes around it, which still just contributes to the interpretation by the shell but now it also easily interferes with quotes coming from the previous command.
A better way would be to retrieve the last command by other means, e.g. history
. There are several ways to filter for the last one, here are some examples:
$ echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")'
a-a
$ cmd="$(history -- -2 | head -n1 | cut -c8-)"
$ echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")'
a-a
$ cmd="$(history -w /dev/stdout | tail -n2 | head -n1)"
$ echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")'
a-a
$ cmd="$(HISTTIMEFORMAT="$(echo -e '\r\e[K')" history -- -2 | head -n1)"
All these examples assign the content of the last command to a shell variable:
$ printf '%s\n' "$cmd"
echo '["a-a","b-a"]' | jq -rc '.[]|select(.=="a-a")'
Alternatively, instead of using an assignment cmd="$(…)"
, you can also redirect it to a file, e.g. … > file
, or pipe it into the another processor, e.g. … | sh
, etc.