Grep别名-行号,除非它在管道中


25

我想为grep创建一个bash别名,添加行号:

alias grep='grep -n'

但这当然也会在管道中添加行号。大多数时候(并且没有例外),我不希望管道中的行号(至少在内部,如果最后是行,可能还可以),而且我也不想添加sed / awk / cut只是为了将它们取出来。

也许我的要求可以简化为“仅当grep是该行上的唯一命令时才添加行号”。没有特别丑陋的别名,有没有办法做到这一点?

Answers:


27

您可以在bash(或任何POSIX shell)中使用如下函数:

grep() { 
    if [ -t 1 ] && [ -t 0 ]; then 
        command grep -n "$@"
    else 
        command grep "$@"
    fi
}

[ -t 1 ]部件使用[命令(也称为test检查stdout是否与tty相关联。

[ -t 0 ]检查标准输入,以及,因为你指定的,只添加行号,如果grep在管道命令。


5
[[ -t 0 && -t 1 ]]如果仅在标准输入和标准输出都连接到端子的情况下只需要行号,则进行测试。
吉尔(Gilles)'所以

3

(为了完整性)

尽管@enzotib的答案很可能是您想要的,但并非您所要的。[ -t 1 ]检查文件描述符是否是终端设备,而不是管道以外的其他设备(例如常规文件,套接字,其他类型的设备,例如/dev/null...)

[命令-t只对管道有效。要获取与文件描述符关联的文件的类型,您需要对其执行fstat()系统调用。没有标准命令可以执行此操作,但是某些系统或Shell包含一些命令。

使用GNU stat

grep() {
  if { [ "$(LC_ALL=C stat -c %F - <&3)" = fifo ]; } 3>&1 ||
     [ "$(LC_ALL=C stat -c %F -)" = fifo ]; then
    command grep "$@"
  else
    command grep -n "$@"
  fi
}

或with zsh和它自己的stat内建函数(比GNU的内置函数早几年),在这里zstat仅作为加载:

grep() {
  zmodload -F zsh/stat b:zstat
  local stdin_type stdout_type
  if zstat -A stdin_type -s -f 0 +mode &&
     zstat -A stdout_type -s -f 1 +mode &&
     [[ $stdin_type = p* || $stdout_type = p* ]]
  then
     command grep "$@"
  else
     command grep -n "$@"
  fi
}

现在几点注意事项:

使用管道的不仅是外壳管道

var=$(grep foo bar)

要么:

cmd <(grep foo bar)

要么:

coproc grep foo bar

还可以grep通过其stdout进入管道。

如果您的shell是ksh93,请注意,在某些系统上,它使用套接字对而不是其管道中的管道。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.