xargs with command that open editor leaves shell in weird state

前端 未结 5 878
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-04 04:27

I tried to make an alias for committing several different git projects. I tried something like

cat projectPaths | \\
xargs -I project git --git-dir=project/.gi         


        
相关标签:
5条回答
  • 2021-02-04 04:54

    The problem is that since you're running xargs (and hence git and hence vim) in a pipeline, its stdin is taken from the output of cat projectPaths rather than the terminal; this is confusing vim. Fortunately, the solution is simple: add the -o flag to xargs, and it'll start git (and hence vim) with input from /dev/tty, instead of its own stdin.

    0 讨论(0)
  • 2021-02-04 04:59

    Using the simpler example of

    ls *.h | xargs vim
    

    here are a few ways to fix the problem:

    xargs -a <( ls *.h ) vim
    

    or

    vim $( ls *.h | xargs )
    

    or

    ls *.h | xargs -o vim
    

    The first example uses the xargs -a (--arg-file) flag which tells xargs to take its input from a file rather than standard input. The file we give it in this case is a bash process substitution rather than a regular file.

    Process substitution takes the output of the command contained in <( ) places it in a filedescriptor and then substitutes the filedescriptor, in this case the substituted command would be something like xargs -a /dev/fd/63 vim.

    The second command uses command substitution, the commands are executed in a subshell, and their stdout data is substituted.

    The third command uses the xargs --open-tty (-o) flag, which the man page describes thusly:

    Reopen stdin as /dev/tty in the child process before executing the command. This is useful if you want xargs to run an interactive application.

    If you do use it the old way and want to get your terminal to behave again you can use the reset command.

    0 讨论(0)
  • 2021-02-04 05:01

    The man page for GNU xargs shows a similar command for emacs:

    xargs sh -c 'emacs "$@" < /dev/tty' emacs
    

    (in this command, the second "emacs" is the "dummy string" that wisbucky refers to in a comment to this answer)

    and says this:

       Launches  the  minimum  number of copies of Emacs needed, one after the
       other, to edit the files listed on xargs' standard input.  This example
       achieves the same effect as BSD's -o option, but in a more flexible and
       portable way.
    

    Another thing to try is using -a instead of cat:

    xargs -a projectPaths -I project git --git-dir=project/.git --work-tree=project commit -a
    

    or some combination of the two.

    0 讨论(0)
  • 2021-02-04 05:11

    If you have GNU Parallel http://www.gnu.org/software/parallel/ installed you should be able to do this:

    cat projectPaths |
    parallel -uj1 git --git-dir={}/.git --work-tree={} commit -a
    

    In general this works too:

    cat filelist | parallel -Xuj1 $EDITOR
    

    in case you want to edit more than one file at a time (and you have set $EDITOR to your favorite editor).

    -o for xargs (as mentioned elsewhere) only works for some versions of xargs (notably it does not work for GNU xargs).

    Watch the intro video to learn more about GNU Parallel http://www.youtube.com/watch?v=OpaiGYxkSuQ

    0 讨论(0)
  • 2021-02-04 05:20

    Interesting! I see the exact same behaviour on Mac as well, doing something as simple as:

    ls *.h | xargs vim

    Apparently, it is a problem with vim:

    http://talideon.com/weblog/2007/03/xargs-vim.cfm

    0 讨论(0)
提交回复
热议问题