Ignore empty results for xargs in Mac OS X

前端 未结 4 1993
迷失自我
迷失自我 2021-02-07 10:36

The code for my website uses this piece of code for automatic deployment on the server (Ubuntu).

cmd = \'cd \' + checkout_dir + \' && \' +

相关标签:
4条回答
  • 2021-02-07 11:14

    Not pretty, but hopefully a workaround.

    cmd = 'cd ' + checkout_dir + ' && ' + 
        'r=$(' svn_command + ' st | ' +
            "awk '$2 !~ /^deploy/{print $2}' | tac) && " +
        'test "$r" && ' +
        svn_command + ' revert -R $r && ' +
        svn_command + ' up -r ' + options.revision
    

    I'm not convinced that the tac is necessary or useful. I refactored the first grep into the Awk script for efficiency and aesthetic reasons.

    To solve the general "my xargs lacks -r" problem, the gist of the solution is to convert

    stuff | xargs -r cmd
    

    into

    var=$(stuff)
    test "$var" && cmd $var
    

    The unquoted $var will only work if it doesn't contain file names with spaces or other surprises; but then bare-bones xargs without the GNU extensions suffers from the same problem.

    0 讨论(0)
  • 2021-02-07 11:27

    The -r for xargs isn't working on OS X, since it's a GNU extension. As for workaround, you should specify some dummy file which can be parsed by xargs or to not call command when there are no arguments (which can be checked before).

    Method using temporary file (or any other placeholder):

    some_cmd ... | xargs svn revert $(mktemp)
    

    Using condition in shell:

    files=$(cd checkout_dir && ... | tac)
    if [ -n "$files" ]; then
        echo $files | xargs && ...
    fi
    

    See also: Ignore empty result for xargs

    0 讨论(0)
  • 2021-02-07 11:33

    Indeed, the BSD implementation of xargs doesn't have the -r flag (--no-run-if-empty). The GNU version in Linux has it.

    Here's one way to work around the issue in a way that works in both Linux and BSD:

    ... | (grep -v ^deploy || echo :) | xargs svn revert
    

    The grep ... || echo : in the middle will generate a line with a : in it in case the output of grep is empty. It's a bit dirty, because xargs will still run the command svn revert :. If your repository doesn't contain the file : then this should have no effect, so it can be acceptable. The : could be anything else, as long as there is no such file in your repository.

    Finally, as @tripleee pointed out, the grep ... || echo : must be enclosed within (...), because:

    the || has higher precedence than |, and thus terminates the (first) pipeline.

    Your code looks like a Python string. It will be more readable this way:

    kwargs = {
      'svn': svn_command,
      'dir': checkout_dir,
      'revno': options.revision,
    }
    cmd = "cd {dir} && {svn} st | awk -v r=1 '$2 ! ~ /deploy/ {{ print $2; r=0 }} END {{ r || print \":\" }}' | xargs {svn} revert && {svn} up -r {revno}".format(**kwargs)
    

    I made some changes to your original:

    • Moved the logic of the grep inside awk, as @tripleee suggested. Notice that since the grep hack is not needed anymore, there is also no more need to wrap within (...)
    • Dropped the tac, as I don't see the point in it
    • Dropped the -R from svn revert, because I don't think you need it
    0 讨论(0)
  • 2021-02-07 11:38

    Bash reimplementation of xargs dealing with the -r argument:

    #!/bin/bash
    stdin=$(cat <&0)
    if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
    then
        # shift the arguments to get rid of the "-r" that is not valid on OSX
        shift
        # wc -l return some whitespaces, let's get rid of them with tr
        linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]') 
        if [ "x$linecount" = "x0" ]
        then
          exit 0
        fi
    fi
    
    # grep returns an error code for no matching lines, so only activate error checks from here
    set -e
    set -o pipefail
    echo $stdin | /usr/bin/xargs $@
    
    0 讨论(0)
提交回复
热议问题