0

TLDR:

cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs') # freezes

# I can't use this because I need to pipe the output of the bind
cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs' &) # doesn't freeze

# I can use this. This won't work for comm below since it takes two file inputs.
cat < <(INPUTRC=/dev/null bash -c 'bind -pm emacs') # doesn't freeze

# I can use this.
cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs') & fg # doesn't freeze

# I can use this. This is my current solution
cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs') | cat # doesn't freeze

Why does it freeze and why does backgrounding fix it? This says it has something to do with EOF, so it would be waiting on stdin. Is there a way to inject an EOF? And why would it be missing an EOF?


I don't know if this is a bug or if I'm doing something wrong.

I using bash-4.4.12(1)-release on macOS but I tested using gnu-grep and gnu-sort on and got the same results.

I am trying to compare the default bindings of bash using process substitution so I don't have to create extra files.

This is how I am getting the default bindings for emacs. I run a bash command with an empty INPUTRC. The grep is to remove unneeded bindings and the sort is so i can compare these emacs bindings with the vi ones using comm later. I got this command from here.

INPUTRC=/dev/null bash -c 'bind -pm emacs' |
LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
sort

Similarly, here's how to get the default vi-insert bindings. Just replace emacs with vi-insert

INPUTRC=/dev/null bash -c 'bind -pm vi-insert' |
LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
sort

Okay now I want to compare these two with comm so I wrap those two commands with process substitution and run comm on them.

comm \
  <(INPUTRC=/dev/null bash -c 'bind -pm emacs' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) \
  <(INPUTRC=/dev/null bash -c 'bind -pm vi-insert' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort)

output:

bash: line 0: bind: warning: line editing not enabled
bash: line 0: bind: warning: line editing not enabled
... (empty. I have to press CTRL+C to exit)

To keep it simple for now, this also freezes

cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs')

So I found this which says backgrounding with & helps, and it does work.

cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs' &) # works, has output, no freeze

So now I try to apply this knowledge to the original command but I can't because there's a pipe.

...'bind -pm emacs' &|... # doesn't work
...'bind -pm emacs' |&... # doesn't work, this is for redirecting stderr to stdout

So then I try backgrounding the whole thing entirely. Append & at the very end of that long command. fg it immediately to keep it a one line command. This works

comm \
  <(INPUTRC=/dev/null bash -c 'bind -pm emacs' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) \
  <(INPUTRC=/dev/null bash -c 'bind -pm vi-insert' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) & fg

Piping to cat also fixes it

comm \
  <(INPUTRC=/dev/null bash -c 'bind -pm emacs' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) \
  <(INPUTRC=/dev/null bash -c 'bind -pm vi-insert' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) | cat

I noticed that when I try closing the terminal with the freezing command, those processes are still running. So CTRL+C doesn't stop those commands image

Does anybody know what's going on?

  • 1
    I have a weird suggestion: what happens if you extend the command you're passing to bash -c to be 'bind -pm whatever; true'? – Wildcard Dec 18 '17 at 23:40
  • Looks like I get the same results. cat <(INPUTRC=/dev/null bash -c 'bind -pm emacs; true') freezes. Also freezes in the giant comm command when you do bash -c 'bind -pm emacs; true' and bash -c 'bind -pm vi-insert; true' in file1 and file2 respectively. – dosentmatter Dec 18 '17 at 23:47
  • 1
    Okay, next question: why use bash -c at all? What's wrong with INPUTRC=/dev/null bind -pm emacs | whatever? – Wildcard Dec 18 '17 at 23:50
  • 1
    The goal of setting INPUTRC to /dev/null is to get the default bindings of the shell, ignoring my current bindings. You get different results with that command. bash uses readline which reads the file specified by INPUTRC (defaults to ~/.inputrc if unset) on startup. If you don't start bash, INPUTRC is not reread. You can use bind -f to read keybindings from a file. But that doesn't unbind keys that were applied after the defaults and reads bindings into the current shell. – dosentmatter Dec 19 '17 at 0:51

Your Answer

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

Browse other questions tagged or ask your own question.