【问题标题】:xargs' $1 conflicts with $1 in shell scriptxargs 的 $1 与 shell 脚本中的 $1 冲突
【发布时间】:2012-11-14 04:15:58
【问题描述】:

我在一个 shell 脚本文件 foo.sh 中有这些行:

ps ax | grep -E "bar" | grep -v "grep" | awk '{print $1}' | xargs kill -9 $1

当我使用这样的参数执行 shell 脚本时:

sh foo.sh arg_one

xargs 现在无法工作。它从 shell 脚本中获取 $1 而不是 awk 的输出。

我知道我可以将 awk 的输出存储到一个文件中,然后在 xargs 中使用它。

但是,有没有更好的解决方案?

== 已编辑 ==

感谢@peterph 的回答。 但是,有什么方法可以在 xargs 中使用 $1 吗?

== 已编辑 2 ==

感谢@Brian Campbell

不管天气如何,示例中应该有一个无用的 $1,如果给出“shell 脚本文件”的参数,那么 xargs 中的 $1 将无法按我的意愿工作,在我的计算机中(在你的计算机中,我思考)。 为什么?还有,如何避免呢?

【问题讨论】:

  • 如果您需要 xargs 中的文件名占位符,请使用 -I 选项——例如xargs -I X cp X X.bak -- 查看手册页
  • @glennjackman 是的,你说得对。我已经检查了手册然后给出了这个问题:shell(或unix)的机制是什么?
  • 机制是shell expansions,发生在命令执行之前。

标签: linux shell arguments xargs


【解决方案1】:

xargsstdin 读取列表,所以如果您想要通过 PID 杀死进程,只需丢弃最后一行的$1

附带说明,ps 还可以根据命令名称打印进程(Linux 上的 procps 参见-C 选项)。

【讨论】:

  • @dennisyuan 不,但是对于您特定的单线,您不需要它。您可以直接删除 $1,它会杀死 awk 打印出来的所有 PID。
  • @nos 是的,你说得对。但是为什么 $1 在没有来自 shell 脚本的参数时起作用,而在有一个参数时不起作用?
  • @dennisyuan $1 在这种情况下有效,因为 $1 是空的,所以你最终会实际运行 xargs kill -9 ,就像你放弃 $1 时一样
  • @nos 我考虑过。似乎 xargs 不能“重用”或“重写”$1,因为已经有一个不为空的 $1,对吧?对于这个奇怪的问题(或功能),shell(或 unix)的机制是什么?
  • @dennisyuan shell 尽可能地扩展变量。我不确定您希望 xargs 与 $1 做什么, xargs 对变量或 $1 应该意味着什么一无所知。 (与 awk 不同,$1 的含义与 shell 中的不同。由于您的 awk 程序用单引号括起来,因此 shell 不会在这些引号内扩展变量)
【解决方案2】:

这应该可行:

ps ax | grep -E "bar" | grep -v "grep" | awk '{print $1}' | xargs kill -9

【讨论】:

    【解决方案3】:

    你总是可以使用killall -9 name 来杀死一个进程,而不是那个复杂的管道,或者如果你不知道进程的确切名称但知道一个子字符串,则可以使用pkill -9 pattern(注意不要杀死但是,任何意外的过程)。

    要使您的命令正常工作,只需删除 $1; xargs 从标准输入中获取参数,并运行命令行,在命令末尾传入它从标准输入中获取的值。

    编辑(响应您的编辑):您希望xargs$1 参数做什么?你希望在里面有什么?对$1 唯一有意义的解释是传递给脚本的第一个参数。

    来自awk 脚本的$1awk 在其输入的第一列中找到的内容;然后将其打印出来,xargs 从标准输入中获取这些值,并在命令行末尾使用这些值调用您传递的命令。所以如果awk 命令返回:

    100
    120
    130
    

    然后将结果传递给xargs kill -9 将导致调用以下内容:

    kill -9 100 120 130
    

    您不需要像 $1 这样的变量来完成这项工作

    【讨论】:

    • 可能有几个进程包含 bar.另一方面,我不明白他为什么为扩展的正则表达式添加-E...
    • 另外,请注意,某些操作系统(尤其是 Solaris)有一个 killall,它的作用完全不同 - 即它会杀死所有东西,而不管任何命令行参数。 (我知道这被标记为“linux”,但仍然......)。
    • @alinsoar killallpkill 都会杀死所有匹配的进程。
    • @twalberg 是的,我认为killall 是安全的,因为他指定了 Linux。但是你的权利,你应该在使用它之前检查你有哪一个。
    • @Brian : killall 匹配全名,而不是子字符串等
    【解决方案4】:

    你也可以试试:

    result=$(ps -ef | grep -E "bar" | grep -v "grep" | awk '{print $2}')
    kill -9 $result
    

    在我的情况下,即使存在匹配的进程,管道 xargs 有时也会返回以下错误:

    usage: kill [ -s signal | -p ] [ -a ] pid ...
           kill -l [ signal ]
    usage: kill [ -s signal | -p ] [ -a ] pid ...
           kill -l [ signal ]
    

    【讨论】:

      猜你喜欢
      • 2012-03-22
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 2019-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多