0

I have the following Bash script

set -o histexpand
set -o history
pwd
lc="!!"

which, when I run it in an interactive shell, prints

/home/user
lc="pwd"

I'd like to, instead of getting lc=pwd, get the last command used in the interactive shell by using history expansion. So if I run echo foo; ./script, I hope to get

/home/user
lc="echo foo"

I tried to set -H in the script and it doesn't work.

  • Wouldn't the last command run in the interactive shell just be the script? $0 should work. $0 "$@" if options are being used – Jesse_b Feb 23 at 14:47
  • @Jesse_b I think this depends on the shell, but that's just a detail because I could set lc="!-2". – History_expansion Feb 23 at 15:00
  • 2
    And what would you expect that to be? The last command ran in the interactive shell session from which the script was launched? What if the script isn't launched from an interactive shell? This feels like an XY problem, could you explain what your final objective is here? – terdon Feb 23 at 15:36
  • Hi, terdon. My primary goal rests on black box details I'm unable to give, and I already found a workaround. Presently what I really want is to satisfy this curiosity (the one that I'm asking about). It's not a XY problem anymore. I'm setting as a condition (I do so in the question) that the script is ran from an interactive shell. – History_expansion Feb 23 at 15:41
  • 1
    I'm pretty sure you won't be able to do what you want without parsing the history file: if the interactive shell has not written its history to the file, then a child shell (your script) will not have access to the recent history of the parent shell. It's a different story if your source your script, but then you have to account for the commands in the script. – glenn jackman Feb 23 at 18:05
2

Using the shell's history expansion for getting the commands executed in the shell session previous to running your script would not be doable unless the invoking shell saves its history to $HISTFILE after each executed command, which bash does not do by default, and exported the HISTFILE variable, which it does not need to do.

By default, the bash shell maintains an in-memory history for the current interactive shell session. This history is saved to $HISTFILE when the shell session exits. When a new session that enables command line history starts, the saved history is read from that file (assuming that new shell uses the same $HISTFILE value).

Your script, unless it has the HISTFILE variable inherited from its invoking environment, will at most be able to access command line history of its own session, i.e. the commands in the script. If HISTFILE is exported, but if the invoking shell never saved its history to $HISTFILE before running the script, it would be impossible to get at the in-memory history of that parent shell session, and you would at most be able to access the historical history of sessions long since dead.

  • Thanks. I'm confused because I can access the interactive's shell history. Running the following script from a file will echo the last command in the interactive shell lc=$(history | tail -2 | head -1 | cut -d" " -f 4); echo $lc. Doesn't this contradict what you said? Or maybe I should ask what's different between history and history expansion that makes my comment and your answer non-contradictory? – History_expansion Feb 23 at 20:30
  • @History_expansion I don't think it contradicts what I was saying. I don't know under what circumstances you run that, but without explicitly running history -a in the shell before executing the script (having the script use the same $HISTORYFILE value and using set -o history), you would not get the invoking shell's up to date history. – Kusalananda Feb 23 at 20:36
  • Can you please see pastebin.com/pwLVhDxy ? Isn't this evidence that it works as I say it does? – History_expansion Feb 23 at 20:47
  • @History_expansion I don't know where you get that echo from in the output. I'm assuming you wanted to get echo $-? This is what happens when I run: pastebin.com/aL0rGfpd – Kusalananda Feb 23 at 21:06
  • You're right about me wanting the whole command, I messed up with the cut. If I run using bash instead of the active shell (which in my case is Bash), I get the same as you. Otherwise it works like we can see in the link I shared. – History_expansion Feb 23 at 22:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.