【问题标题】:Ignore empty results for xargs in Mac OS X忽略 Mac OS X 中 xargs 的空结果
【发布时间】:2013-06-28 10:46:07
【问题描述】:

我网站的代码使用这段代码在服务器(Ubuntu)上自动部署。

cmd = 'cd ' + checkout_dir + ' && ' + svn_command + " st | awk '{print $2}' | grep -v ^deploy | tac | xargs -r" + svn_command + " revert -R && " + svn_command + ' up -r ' + options.revision

此命令的作用是将cd 放入结帐目录,运行svn status,然后提取文件名($2),从列表中删除deploy 目录及其所有文件(我没有想恢复它)。如果没有参数它不会运行 svn revert 命令,否则它会运行。

很遗憾,xargs -r 在我的机器(Mac OS X 10.8)上不起作用。所以我被困在这里,有人可以帮忙吗?

【问题讨论】:

  • 那是 Python 代码还是什么?

标签: macos shell svn awk xargs


【解决方案1】:

确实,xargs 的 BSD 实现没有 -r 标志 (--no-run-if-empty)。 Linux 中的 GNU 版本有它。

这是一种在 Linux 和 BSD 中都有效的解决问题的方法:

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

如果grep 的输出为空,中间的grep ... || echo : 将生成一个带有: 的行。这有点,因为xargs 仍然会运行命令svn revert :。如果您的存储库不包含文件:,那么这应该无效,因此可以接受。 : 可以是其他任何东西,只要您的存储库中没有这样的文件。

最后,正如@tripleee 所指出的,grep ... || echo : 必须包含在(...) 中,因为:

|| 的优先级高于|,因此会终止(第一个)管道。

您的代码看起来像一个 Python 字符串。这样会更易读:

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)

我对你的原作做了一些修改:

  • 按照@tripleee 的建议,将grep 的逻辑移到awk 中。请注意,由于不再需要 grep hack,因此也不再需要包装在 (...)
  • 删除了tac,因为我看不出其中的意义
  • svn revert 中删除了-R,因为我认为你不需要它

【讨论】:

  • 这有什么帮助?问题不是空行,而是 no 行。
  • @tripleee 他想使用xargs-r 标志,但不能,因为它在BSD 中不存在。他想使用标志,因为他不想在没有参数的情况下运行svn revert -Rsvn revert -R something 将仅还原“某物”中的更改,而不带参数的 svn revert -R 将还原所有内容。他不想恢复一切。
  • 我理解这个问题。 xargs -r 用于在没有输入时抑制动作; grep . 在没有输入时不会生成任何输入(怎么可能?),所以这个答案中建议的解决方法根本没有帮助。
  • @tripleee aaaaaaaah,好的,我明白了!你完全正确,我纠正了我的答案。
  • 还不完全在那里;您将需要像( cmds || echo : ) | xargs 这样的管道括号,因为|| 具有更高的优先级tjan | 并因此终止(第一个)管道。
【解决方案2】:

不漂亮,但希望是一种解决方法。

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

我不相信tac 是必要的或有用的。出于效率和美观的原因,我将第一个 grep 重构为 Awk 脚本。

要解决一般的“我的xargs 缺少-r”的问题,解决方案的要点是转换

stuff | xargs -r cmd

进入

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

未引用的$var 仅在不包含带空格或其他意外的文件名时才有效;但是没有 GNU 扩展的准系统 xargs 也会遇到同样的问题。

【讨论】:

    【解决方案3】:

    xargs-r 不适用于 OS X,因为它是 GNU 扩展。至于解决方法,您应该指定一些可以被xargs 解析的虚拟文件,或者在没有参数时不调用命令(可以在之前检查)。

    使用临时文件(或任何其他占位符)的方法:

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

    在shell中使用条件:

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

    另请参阅:Ignore empty result for xargs

    【讨论】:

      【解决方案4】:

      xargs 处理 -r 参数的 Bash 重新实现:

      #!/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 $@
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-22
        • 2015-04-07
        • 2011-02-07
        • 2012-01-07
        • 1970-01-01
        相关资源
        最近更新 更多