I want to run a command and see all of its output on the left hand side, while simultaneously searching/grepping for particular lines on the right hand side. In other words, I want a temporary vertically split screen in my CLI, ideally with scrollback on each side of the split, but where I expect the left hand side to be scrolling thousands of lines quickly, while on the right hand side is a slow accumulation of “matches” to my grep.

Is this possible today? What tools would you recommend to accomplish this?

EDIT: To be clear, a one-liner is preferable over learning tmux or screen, although this does motivate me to perhaps begin learning tmux.

In case this is an X/Y problem: The specific command I’m trying to run is an rsync simulation (dry-run) where I want to both check that the command works, and subsequently check that there are no denied errors. The recommended way to do this is to run the command twice, as follows (but I want to combine it into one pass):

# first specify the "-n" parameter so rsync will simulate its operation. You should use this before you start:
rsync -naP --exclude-from=rsync-homedir-local.txt /home/$USER/ $BACKUPDIR/

# check for permission denied errors in your homedir:
rsync -naP --exclude-from=rsync-homedir-local.txt /home/$USER/ $BACKUPDIR/ | grep denied
  • lemmyvore@feddit.nl
    link
    fedilink
    English
    arrow-up
    42
    ·
    edit-2
    11 months ago

    Run rsync, pipe to tee, and redirect the output to a named pipe (mkfifo). Open a second terminal and direct the named pipe into a grep command. Arrange the terminals in whatever way you want.

    mkfifo mypipe
    rsync | tee mypipe
    grep "denied" < mypipe
    
  • notabot@lemm.ee
    link
    fedilink
    arrow-up
    25
    ·
    11 months ago

    Tmux is a very helpful terminal multiplexer, meaning it can split your terminal into multiple panes. So, create two side by side panes, then one way of doing it is:

    • on the left, run your cmd | tee >(grep 'denied' > error.log)
    • on the right, run tail -f error.log

    The tee process takes it’s standard in, and writes itbto both standard out, so you see all the lines, and the path it’s been given. The >(...) operator runs the grep in a subprocess, and returns the path to it’s standard input pipe, so grep receives every line, and writes the denied lines to a log file which you display with tail in the other pane.

    Rather than using a file for error.log you could also use a named pipe in much the same way.

    • canadaduaneOP
      link
      fedilink
      English
      arrow-up
      1
      ·
      11 months ago

      Thanks! I’m curious if there is a way to do this as a one-liner?

      • notabot@lemm.ee
        link
        fedilink
        arrow-up
        2
        ·
        11 months ago

        Sorry for th slow answer, I’ve been away. There is a way, if it’s still useful to you:

        First, create a named fifo, you only need to do this once:

        mkfifo logview
        

        Run your rsync in one pane, with a filtered view in the second:

        tmux new 'rsync ...options... |& tee logview' \; split-window -h 'grep "denied" logview'
        

        Replace ...options... with your normal rsync command line.

        That should give you a split view, with all the normal messages on the left, and only messages containing ‘denied’ on the right.

        The |& makes sure we capture both stdout and stderr, tee then writes them to the fifo and displays them. split-window tells tmux to create a second pane, and display the output of grep.

  • canadaduaneOP
    link
    fedilink
    English
    arrow-up
    8
    ·
    11 months ago

    Given encouragement to try tmux, here is what I’ve come up with as a “one-liner” (script) that does what I was originally looking for:

    #!/bin/sh
    
    tmux new-session -d -s split_screen_grep \; \
      send-keys "/bin/sh -c '$1' | tee /tmp/split_screen_grep.txt" C-m \; \
      split-window -h \; \
      select-pane -t 1 \; \
      send-keys "tail -f /tmp/split_screen_grep.txt | grep '$2'" C-m \;
    
    tmux attach-session -t split_screen_grep
    

    I use it as follows, first arg is a command, second arg is a pattern to search for:

    $ ./split-grep "cat big_file.txt" "tmux"
    
  • Björn Tantau@swg-empire.de
    link
    fedilink
    arrow-up
    7
    ·
    11 months ago

    I usually solve this kind of problem by piping to less or a logfile and then just searching in there. You can get it to refresh new content by pressing the End key twice. Or maybe less just needs the -f flag or something similar. I’m too lazy to look it up.

  • canadaduaneOP
    link
    fedilink
    English
    arrow-up
    6
    arrow-down
    2
    ·
    11 months ago

    ChatGPT suggests the following:

    1. Run tmux
    2. rsync -naP --exclude-from=rsync-homedir-local.txt /home/$USER/ $BACKUPDIR/ | tee /tmp/rsync_output.txt
    3. Ctrl+B % # splits screen vertically
    4. Ctrl+B right-arrow-key # moves to right split
    5. tail -f /tmp/rsync_output.txt | grep denied

    Not quite a one-liner, but I can see how tmux is a big help here.

    • mkwarman@lemmy.mkwarman.com
      link
      fedilink
      arrow-up
      7
      ·
      11 months ago

      I know this isn’t an answer you’re looking for, but I’ll at least say that I find tmux to be infinitely useful and highly recommend checking it out

    • s38b35M5@lemmy.world
      link
      fedilink
      English
      arrow-up
      6
      ·
      11 months ago

      Tmux is also good for long operations, as tmux is running as a server and you can close the terminal while tmux chugs away. Others can also connect to the tmux session through ssh and share screens.

  • PenguinCoder@beehaw.org
    link
    fedilink
    English
    arrow-up
    2
    ·
    edit-2
    11 months ago

    Your request goes against the unix philosophy. Grep does one thing and does it well. If you desire additional functionality, you should add another utility to accomplish what you want.

    rsync -naP --exclude-from=rsync-homedir-local.txt /home/$USER/ $BACKUPDIR/ | grep denied

    In your specific task, utilize bashims to do (what I think) you want:

    rsync -naP --exclude-from=rsync-homedir-local.txt /home/$USER/ $BACKUPDIR/ || echo "task failed"