Grep alias - numéros de ligne sauf s'il est dans un pipeline

25

Je veux créer un alias bash pour grep qui ajoute des numéros de ligne:

alias grep='grep -n'

Mais cela, bien sûr, ajoute également des numéros de ligne aux pipelines. La plupart du temps (et aucune exception ne me vient à l'esprit), je ne veux pas de numéros de ligne dans un pipeline (au moins en interne, probablement OK si c'est le dernier), et je ne veux pas vraiment ajouter un sed / awk / cut à le pipeline juste pour les retirer.

Peut-être que mes exigences pourraient être simplifiées pour «ajouter des numéros de ligne uniquement si grep est la seule commande sur la ligne». Existe-t-il un moyen de le faire sans un alias particulièrement laid?

Kevin
la source

Réponses:

27

Vous pouvez utiliser une fonction en bash (ou n'importe quel shell POSIX) comme ceci:

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

La [ -t 1 ]pièce utilise la [commande (également appelée test) pour vérifier si stdout est associé à un tty.

Le [ -t 0 ]vérifie également l'entrée standard, puisque vous avez spécifié d'ajouter uniquement des numéros de ligne si grepest la seule commande dans le pipeline.

enzotib
la source
5
Et faites le test [[ -t 0 && -t 1 ]]si vous ne voulez des numéros de ligne que si l'entrée standard et la sortie standard sont connectées à un terminal.
Gilles 'SO- arrête d'être méchant'
3

(pour être complet)

Bien que la réponse de @ enzotib soit probablement ce que vous voulez, ce n'est pas ce que vous avez demandé. [ -t 1 ]vérifie si le descripteur de fichier est un périphérique terminal, et non pas autre chose qu'un tube (comme un fichier normal, une socket, un autre type de périphérique comme /dev/null...)

La [commande n'a pas d'équivalent -tmais pour les tuyaux. Pour obtenir le type du fichier associé à un descripteur de fichier, vous devez effectuer l' fstat()appel système sur celui-ci. Il n'y a pas de commande standard pour le faire, mais certains systèmes ou shells en ont.

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

Ou avec zshet son propre statintégré (qui est antérieur à celui de GNU de quelques années), ici chargé zstatuniquement:

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
}

Maintenant quelques notes:

Ce ne sont pas seulement les pipelines shell qui utilisent des tuyaux.

var=$(grep foo bar)

ou:

cmd <(grep foo bar)

ou:

coproc grep foo bar

aussi courir grepavec sa sortie standard vers un tuyau.

Si votre shell l'est ksh93, notez que sur certains systèmes, il utilise des paires de sockets au lieu de tuyaux dans ses pipelines.

Stéphane Chazelas
la source