Grep alias - numery linii, chyba że są w przygotowaniu

25

Chcę utworzyć alias bash dla grep, który dodaje numery wierszy:

alias grep='grep -n'

Ale to oczywiście dodaje również numery linii do rurociągów. Przez większość czasu (i nie przychodzą mi na myśl żadne wyjątki) Nie chcę numerów linii w potoku (przynajmniej wewnętrznie, prawdopodobnie OK, jeśli jest ostatni) i nie chcę dodawać sed / awk / cut do rurociąg tylko po to, aby je wyjąć.

Być może moje wymagania mogłyby zostać uproszczone, aby „dodawać numery linii tylko wtedy, gdy grep jest jedynym poleceniem w linii”. Czy można to zrobić bez szczególnie brzydkiego pseudonimu?

Kevin
źródło

Odpowiedzi:

27

Możesz użyć funkcji w bash (lub dowolnej powłoce POSIX) w następujący sposób:

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

[ -t 1 ]Część wykorzystuje [polecenie (znany również jako test) , aby sprawdzić, czy standardowe wyjście jest związane z terminalem.

[ -t 0 ]Sprawdza standardowe wejście, jak również, ponieważ określona tylko dodać numery linii, jeśli grepjest tylko komenda w rurociągu.

enzotib
źródło
5
I wykonaj test, [[ -t 0 && -t 1 ]]jeśli chcesz numery linii tylko wtedy, gdy zarówno standardowe wejście, jak i standardowe wyjście są podłączone do terminala.
Gilles 'SO - przestań być zły'
3

(dla pełności)

Chociaż odpowiedź @ enzotib jest najprawdopodobniej tym, czego chcesz, to nie o to prosiłeś. [ -t 1 ]sprawdza, czy deskryptor pliku jest urządzeniem końcowym, a nie tym, że jest czymś innym niż potok (jak zwykły plik, gniazdo, inny typ urządzenia, taki jak /dev/null...)

[Komenda nie ma odpowiednika -t, ale do rur. Aby uzyskać typ pliku skojarzonego z deskryptorem pliku, należy wykonać na nim fstat()wywołanie systemowe. Nie ma do tego standardowego polecenia, ale niektóre systemy lub powłoki mają takie.

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

Albo zshi własny statwbudowany (który poprzedza jeden GNU przez kilka lat), tutaj załadowany jak zstattylko:

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
}

Teraz kilka notatek:

Nie tylko rurociągi powłokowe używają rur.

var=$(grep foo bar)

lub:

cmd <(grep foo bar)

lub:

coproc grep foo bar

także biegnij grepze stdout do rury.

Jeśli twoja powłoka jest ksh93, pamiętaj, że w niektórych systemach używa potoków zamiast potoków w swoich potokach.

Stéphane Chazelas
źródło