2

I have a function (not) that displays a notification. Hence, I can use it to show when a command is complete.

sleep 5; not

However, sometimes I forget to add ;not. In OS X's terminal (a few years ago), I could enter a second command, while the current command was running. This second command would execute after the first had finished.

Thus, I'd type sleep 5Enter, then immediately type notEnter. After sleep had terminated, not would execute.

However, my experience in Linux is that this does not occur. After sleep terminates, the command line shows not, but the Enter never registers. I've tested Terminator, Konsole and a tty.

Is this behaviour dependent on the terminal emulator, and if so, are there any that work as I want? Alternatively, is there a way to make this function work in my terminal of choice (Terminator)?

Testing in different shells

Doesn't work, i.e. the second command doesn't register:

  • bash
  • bash --norc
  • bash --norc --noprofile
  • sh

Does work, i.e. the second command registers:

  • bash --norc --noprofile --noediting
  • zsh

I selectively removed lines from ~/.inputrc and tested with my default bash shell again. I traced the problem to the following line. When removed, the second command registers as expected.

Control-j: menu-complete

Oddly enough, if I try binding (say) Ctrl+i instead, there is no problem. Why does this entry prevent the second command from registering, and is there a way to still use Ctrl+j for menu-complete while having the behaviour that I want for this second command?

  • 2
    I've just checked in konsole. It works as you expected (enter is pressed). – Jshura Jan 16 '16 at 8:23
  • @Jshura Thanks for that. I just tried again in konsole and it's definitely not working. FWIW I tried four iterations of not<Enter>, and got back $ not notnotnot(with that odd spacing). I get the same in Terminator. – Sparhawk Jan 16 '16 at 9:07
  • 1
    which terminal and shell are you using? I've just checked with gnome-terminal, xterm and tty with sh, bash and zsh. All-time works for me – Pandya Jan 16 '16 at 10:44
  • @Pandya I've tested with terminator and konsole, both with bash. – Sparhawk Jan 16 '16 at 12:10
  • oh. bash is the problem. have a look at man termios and PENDIN. – mikeserv Jan 16 '16 at 13:03
1

Well, according to some of your edits you've got CTRL+J bound to a bindkey macro command. That explains your bash issue considering readline's default behavior.

Generally readline reads input in something very like stty raw mode. Input chars are read in as soon as they are typed and the shell's line-editor handles its own buffering. readline sets the terminal to raw when it takes the foreground, and it restores it to whatever its state was beforehand when calling up another foreground process group.

CTRL+J is an ASCII newline. ABCDEFGHIJ is 10 bytes from NUL. Because you have configured readline to eat this character and subsequently to expand away what remains of any command-line on which it does with menu-completion, type-ahead won't work. The terminal is in a different state when the type-ahead is buffered by the kernel's line-discipline than it is when readline is in the foreground.

When readline is in the foreground it does its own translation for input carriage returns -> newlines and the terminal driver doesn't convert it at all. When you enter your type-ahead input, though, the terminal driver will typically translate returns to newlines as can be configured with stty [-]icrnl. And so your return key is sufficient for commands entered live, but the newlines sent by the terminal's line-discipline are being interpreted as menu-complete commands.

You might tell the terminal driver to stop this translation with stty -icrnl. This is likely to take at least a little bit of getting used to. Other commands that accept terminal input will usually expect newlines rather than returns, and so you'll either have to explicitly use CTRL+J when they control the foreground, or else teach them to handle the returns as bash does.

You've already mentioned that read doesn't work as expected when reading form the terminal. Again, it likely would if you explicitly used CTRL+J to end an input line. Or... you can teach it:

read()
    if    [ -t 0 ]
    then  command read -d $'\r' "$@"
    else  command read "$@"
    fi

It will probably be a lot less hassle in the long-run if you found a different key for menu-complete, though. Newlines are kind of a big deal for most terminal applications.

3

Assuming you're using bash: Try hitting ^Z (i.e., Ctrl-Z) to stop the process, move it to the background, and get another bash prompt. Type fg; not, the former continues the stopped process and returns when it finishes.

Alternatively, figure out the proces id of the program you want to wait for, assume it's 2342. In a new shall, type

until kill -0 2342; do sleep 1; done; not

this will check every second.

  • Not a bad idea, but Ctrl+z doesn't always work. For example, if my command is sleep 5; echo foo, sleep is suspended but the echo runs immediately. Or if it's running a for loop, the loop seems to just terminate. Similarly, the second suggestion will fail for chained commands and pipes. – Sparhawk Jan 16 '16 at 13:48

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.