【问题标题】:Bash alias with an argument that works with pipe and globs带有可用于管道和 glob 的参数的 Bash 别名
【发布时间】:2018-05-14 12:12:22
【问题描述】:

我的 bashrc 文件中有一个方便的函数,如下所示:

function get_pattern()
{
    grep "P1" $1 | grep -v "BUT_NOT_THIS" | awk -F":" '{print $(1)}' | sort -u
}

alias gp='get_pattern'

如果我在像gp file_1.c 这样的单个文件上运行它,这会很好。但是我无法像find . -name "*.c" -type f | xargs gp 那样运行它。我也无法像gp *.c 那样运行它。如何编写 get_pattern 代码,以便获得所有这些便利。

注意:我已经简化了函数以便于理解。不期待智能 grep/awk/sed/sort hack 或调整。问题是我有一个将文件名作为参数的别名。希望它与管道一起使用,最好是与 glob 一起使用。

【问题讨论】:

  • 在函数中使用别名是一种反模式!只需单独使用该函数并将参数传递给它
  • 使用别名是一种反模式!
  • Shell 别名最好用作交互式使用的命令行快捷方式,以节省键入时间。它们不适合编写脚本。

标签: bash shell scripting command-line-arguments alias


【解决方案1】:

正如专家所指出的,别名不适合您的要求。

在您的函数中,您只将第一个参数传递给 grep,如 grep "P1" $1。将其更改为使用所有参数,这样:

function get_pattern() {
    grep "P1" "$@" | grep -v "BUT_NOT_THIS" | awk -F":" '{print $(1)}' | sort -u
}

注意:

  • 当您以get_pattern *.c 调用您的函数并且有匹配的文件时,该函数看不到*.c,它会看到匹配文件的列表。 glob 扩展是由 shell 在调用函数时完成的,而不是在函数内部。

  • 在目前的格式中,函数不会从标准输入读取。因此,将另一个命令的结果通过管道传输到您的函数中可能不起作用。要使其接受标准输入,您需要将第一个 grep 更改为:

    grep "P1" - "$@"

当您打算让函数只读取文件时,这会搞乱调用。所以,最好这样重写函数:

function get_pattern() {
    if (($# > 0)); then
        # arguments passed, use them as file names to grep from
        grep_args=("$@")
    else
        # no arguments passed, grep from stdin
        grep_args=(-)
    fi
    grep "P1" "${grep_args[@]}" | grep -v "BUT_NOT_THIS" | awk -F":" '{print $(1)}' | sort -u

}

【讨论】:

  • Linux centos72_base 3.10.0-327.10.1.el7.x86_64 上使用GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)。感谢您的详细回复。 "$@" 使我能够使用 glob。但是您的第二部分解决方案(stdin)对我不起作用。我仍然无法使用echo "file1.c" | gpfind . -name "*.c" -type f | xargs gp
  • 正如@williampursell 所指出的,您不能将别名与 xargs 或管道一起使用。对你的函数做一个export -f get_pattern 并使用函数名本身。
【解决方案2】:

我只关注将数据管道传输到 xargs 的问题。这不起作用,因为 xargs 对别名一无所知。但是,您可以使用export -f 有效地传递函数定义以使其工作(在 bash 和可能的其他一些 shell 中工作的非便携式解决方案,但不要指望它可以在任何地方工作):

$ foo() { echo foo: $@; }
$ echo bar baz | xargs bash -c 'foo $@' _
_: foo: command not found
$ export -f foo
$ echo bar baz | xargs bash -c 'foo $@' _
foo: bar baz

我不知道有任何方法可以使用别名执行此操作,但我也不知道有任何理由使用别名。停止使用别名。

【讨论】:

  • 你的意思是bash -c 'foo "$@"'(带双引号),对吧?
  • @CharlesDuffy,我实际上不确定。在这种情况下,分词将被 xargs 规范化,我认为用这种设置真的没有办法理智地处理空格。 "$@" 可能会给人一种虚假的安全感。
  • 嗯。一个公平的观点——尽管xargs 可以安全地使用,如果利用GNU扩展——例如,如果使用-d $'\n'-0——在这种情况下bash调用将是弱点。
猜你喜欢
  • 2020-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-03
  • 1970-01-01
  • 2011-05-16
  • 2017-06-11
相关资源
最近更新 更多