Issue
I am building a cli tool in node.js (for mac, bash), which lets you interactively construct a command and run it. for example, you can run "node myTool", and then it asks you some questions and at the end runs a command. The thing is, I want the user to be able to run the final command again by pressing the "up" key. currently, when the user presses "up" he gets: "node myTool", but I want instead to give him the actual command that was running. I was able to do it in bash, by manipulating the history like this:
echo 'final command' >> $HISTFILE && history -r $HISTFILE
this actually works, and when I press "up" I see "final command", but It doesn't work from node.js by using execSync:
execSync(`echo 'final command' >> $HISTFILE && history -r $HISTFILE`);
It successfully appends "final command" to the history, but for obvious reasons, "history -r" doesn't refresh the terminal. is there a way to actually refresh the terminal's history for the user to achieve the expected result??
Solution
You're running history -r
in a new shell process, not the user's original interactive shell. Each shell process keeps its own history, and reloading the child shell's history has no effect on the parent shell's history.
In general, there's no direct way to modify the state of the parent shell. Programs that are intended to do this work by outputting shell commands. The user makes use of them by getting the output with a command substitution, then using eval
to execute it (an example of this is tset
).
So you could change your node.js script to
fs.writeFileSync(process.env.HISTFILE, "final command\n", "a");
process.stdout.write(`history -r "$HISTFILE"`);
Then you could use it as
eval "$(node scriptname.js)"
But in this case the script can't do any "normal" output to stdout, since anything it prints will be executed by eval
rather than displayed on the terminal.
Answered By - Barmar Answer Checked By - Willingham (WPSolving Volunteer)