Grep alias: números de línea a menos que esté en una tubería

25

Quiero crear un alias bash para grep que agregue números de línea:

alias grep='grep -n'

Pero eso, por supuesto, agrega números de línea a las tuberías también. La mayoría de las veces (y no se me ocurren excepciones) no quiero números de línea dentro de una tubería (al menos internamente, probablemente esté bien si es el último), y realmente no quiero agregar un sed / awk / cut a la tubería solo para sacarlos.

Quizás mis requisitos podrían simplificarse para "agregar solo números de línea si grep es el único comando en la línea". ¿Hay alguna manera de hacer esto sin un alias particularmente feo?

Kevin
fuente

Respuestas:

27

Puede usar una función en bash (o cualquier shell POSIX) como esta:

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

La [ -t 1 ]parte usa el [comando (también conocido como test) para verificar si stdout está asociado con un tty.

También [ -t 0 ]verifica la entrada estándar, ya que especificó agregar solo números de línea si grepes el único comando en la tubería.

enzotib
fuente
55
Y haga la prueba [[ -t 0 && -t 1 ]]si solo desea números de línea si tanto la entrada estándar como la salida estándar están conectadas a un terminal.
Gilles 'SO- deja de ser malvado'
3

(por completitud)

Si bien la respuesta de @ enzotib es probablemente lo que quieres, no es lo que pediste. [ -t 1 ]comprueba si el descriptor de archivo es un dispositivo terminal, no es otra cosa que una tubería (como un archivo normal, un zócalo, otro tipo de dispositivo como /dev/null...)

El [comando no tiene equivalente -tsino para tuberías. Para obtener el tipo de archivo asociado con un descriptor de archivo, debe realizar la fstat()llamada del sistema en él. No hay un comando estándar para hacer eso, pero algunos sistemas o shells tienen algunos.

Con 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
}

O con zshy su propio statincorporado (que precede a GNU por unos años), aquí cargado como zstatsolo:

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
}

Ahora algunas notas:

No solo las tuberías de concha utilizan tuberías.

var=$(grep foo bar)

o:

cmd <(grep foo bar)

o:

coproc grep foo bar

También se ejecuta grepcon su stdout yendo a una tubería.

Si su shell es ksh93, tenga en cuenta que en algunos sistemas, utiliza pares de enchufes en lugar de tuberías en sus tuberías.

Stéphane Chazelas
fuente