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?

dosentmatter
  • 498
  • 5
  • 12
  • 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 00:51
  • This must be a macOS thing. In debian this works even without piping to `cat`. – thiagowfx Jun 28 '20 at 04:07

0 Answers0