1

I'm trying to spawn a new terminal, execute a few commands and pipe their output to stdin of the original process. A mwe of what I'm trying to do is the following bash one-liner:

$ xterm -e sh -c "echo -e 'foo\nbar' > /proc/$$/fd/1" | grep foo

where I spawn a new xterm window, print foo\nbar and try to redirect it to stdin of the shell I'm executing this command from. To see if it works I then pipe it into grep.

The code above prints both foo and bar to stdout instead of just foo, but I'm not sure why. How can I fix this?

EDIT: the real case implementation of this is a file picker that uses fzf:

#!/usr/bin/env bash

function open() {
  # takes a bunch of file names (either passed as arguments or from stdin) and
  # opens them
  true
}

# This is what I have now
alacritty \
   -e sh -c 'fzf -m --prompt="Open> " --border=horizontal --print0 \
              | (nohup xargs -0 bash -c '\''open "$@"'\'' _ &>/dev/null &)'

# This is what I'm trying to do
# alacritty \
#  -e sh -c "fzf -m --prompt='Open> ' --border=horizontal > /proc/$$/fd/1" \
#  | open
6
  • 2
    Why do you need xterm for this? Your code prints foo and bar because it prints to the original terminal (this is where double-quoted /proc/$$/fd/1 points to). grep gets exactly nothing from xterm. Without redirection to /proc/$$/fd/1 grep would get the same nothing. You would need to find out the stdout of xterm to send something to grep. What are you trying to achieve by running xterm in the first place? Mar 30, 2021 at 22:41
  • There is no stdout from xterm
    – roaima
    Mar 30, 2021 at 22:51
  • @KamilMaciorowski I'm trying to create a file launcher using fzf: I spawn a new terminal with fzf running, select some file, then pipe it into a function that opens it.
    – noibe
    Mar 31, 2021 at 11:44
  • @KamilMaciorowski I've added my actual use case to the question.
    – noibe
    Mar 31, 2021 at 11:55
  • It seems you want to achieve what fzf-tmux does with tmux, but with xterm or alacritty instead. You seem to expect the terminal emulator to print to its stdout whatever the program(s) running inside it print to the terminal. This is not how things work. Note fzf-tmux uses named fifos somehow (I haven't researched thoroughly) to communicate with fzf spawned in a tmux pane. If you really want fzf in a new terminal then you need to do something similar. Can you take it from here? or do you need help in implementing a solution? Mar 31, 2021 at 12:16

2 Answers 2

1

I'm a bit late, but as an alternative to using named pipes (FIFO's), fzf also provides the ability to execute external commands in response to a key binding. This is how I use fzf for a file picker (using xdg-open, which should be available for most Linux distros):

fzf --bind "enter:execute(setsid xdg-open {} 2>/dev/null &)+abort"

You can launch a terminal that executes some variation of the above (e.g. from a global keyboard shorcut). In my dotfiles I have one script for opening files and one for launching GUI programs using gtk-launch. I've been using it for a few months without much issue, but gtk-launch always ignores only the first call after a reboot for some reason.

Anyway, I found this simpler than fiddling with fifos or file descriptors.

-2
#!/bin/sh
exec alacritty -e /bin/sh -c \
  "exec fzf \"\$@\" < /proc/$$/fd/0 > /proc/$$/fd/1" \
  -- "$@" 2>/dev/null
2
  • 1
    We prefer answers that include an explanation. May 8 at 15:39
  • 1
    This is a rather intricate piece of code that requires explanation, if for no other reason than to understand it and to know what to change if it needs to be used for something similar.
    – Kusalananda
    May 8 at 16:01

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.