Grep alias - номера строк, если они не находятся в конвейере


25

Я хочу создать псевдоним bash для grep, который добавляет номера строк:

alias grep='grep -n'

Но это, конечно, добавляет номера строк в конвейеры. Большую часть времени (и на ум не приходит никаких исключений) я не хочу, чтобы номера строк в конвейере (по крайней мере, внутренне, вероятно, были бы в порядке, если он последний), и я действительно не хочу добавлять sed / awk / cut в трубопровод только чтобы вынуть их.

Возможно, мои требования можно было бы упростить так: «добавляйте только номера строк, если grep - единственная команда в строке». Есть ли способ сделать это без особо уродливого псевдонима?

Ответы:


27

Вы можете использовать функцию в bash (или любую оболочку POSIX) следующим образом:

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

[ -t 1 ]Часть использует [команду (также известный как test) , чтобы проверить , если стандартный вывод связан с терминалом.

Также [ -t 0 ]проверяет стандартный ввод, поскольку вы указали добавлять только номера строк, если grepэто единственная команда в конвейере.


5
И сделайте тест, [[ -t 0 && -t 1 ]]если вам нужны только номера строк, если и стандартный вход, и стандартный выход подключены к терминалу.
Жиль "ТАК - перестань быть злым"

3

(для полноты)

Хотя ответ @ enzotib, скорее всего, то, что вы хотите, это не то, что вы просили. [ -t 1 ]проверяет, является ли файловый дескриптор оконечным устройством, а не что-либо, кроме канала (например, обычный файл, сокет, устройство другого типа, например /dev/null...)

Команда [не имеет эквивалента, -tкроме как для труб. Чтобы получить тип файла, связанный с дескриптором файла, вам необходимо выполнить fstat()системный вызов для него. Для этого нет стандартной команды, но некоторые системы или оболочки имеют некоторые.

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

Или с 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, идущим к трубе.

Если ваша оболочка есть ksh93, обратите внимание, что в некоторых системах она использует пары сокетов вместо каналов в своих конвейерах.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.