Подтвердить что ты не робот

Всегда включать первую строку в grep

Я часто встречаю CSV файлы с именами столбцов в первой строке. Поэтому я хочу, чтобы вывод grep всегда включал первую строку (для получения имен столбцов), а также любые строки, соответствующие шаблону grep. Каков наилучший способ сделать это?

4b9b3361

Ответ 1

СЕПГ:

sed '1p;/pattern/!d' input.txt

AWK:

awk 'NR==1 || /pattern/' input.txt

grep1:

grep1() { awk -v pattern="${1:?pattern is empty}" 'NR==1 || $0~pattern' "${2:?filename is empty}"; }

Ответ 2

grep на самом деле не имеет понятия номера строки, но awk делает, поэтому здесь пример строк вывода содержит "Incoming" - и первую строку, что бы это ни было:

awk 'NR == 1 || /Incoming/' foo.csv

Вы можете сделать script (немного чрезмерно, но). Я сделал файл, grep + 1 и поместил его в него:

#!/bin/sh
pattern="$1" ; shift
exec awk 'NR == 1 || /'"$pattern"'/' "[email protected]"

Теперь можно:

./grep+1 Incoming

edit: удалена "{print;}", которая является действием по умолчанию awk.

Ответ 3

Вы можете использовать sed вместо grep для этого:

sed -n -e '1p' -e '/pattern/p' < $FILE

Это будет печатать первую строку дважды, однако, если она содержит шаблон.

-n сообщает sed не печатать каждую строку по умолчанию.
-e '1p' печатает первую строку.
-e '/pattern/p' печатает каждую строку, соответствующую шаблону.

Ответ 4

Это очень общее решение, например, если вы хотите сортировать файл, сохраняя первую строку на своем месте. В принципе, "передайте первую строку через as-is, затем сделайте все, что я хочу (awk/grep/sort/whatever) для остальной части данных."

Попробуйте это в script, возможно, назвав его keepfirstline (не забудьте chmod +x keepfirstline и поместите его в PATH):

#!/bin/bash
IFS='' read -r JUST1LIINE
printf "%s\n" "$JUST1LIINE"
exec "[email protected]"

Его можно использовать следующим образом:

cat your.data.csv | keepfirstline grep SearchTerm > results.with.header.csv

или, возможно, если вы хотите фильтровать с помощью awk

cat your.data.csv | keepfirstline awk '$1 < 3' > results.with.header.csv

Мне часто нравится сортировать файл, но сохраняя заголовок в первой строке

cat your.data.csv | keepfirstline sort

keepfirstline выполняет заданную команду (grep SearchTerm), но только после чтения и печати первой строки.

Ответ 5

Другая опция:

$ cat data.csv | (read line; echo "$line"; grep SEARCH_TERM)

Пример:

$ echo "title\nvalue1\nvalue2\nvalue3" | (read line; echo "$line"; grep value2)

Вывод:

title
value2

Ответ 6

Вы можете включить альтернативное совпадение шаблонов для одного из имен столбцов. Если столбец был назван COL, тогда это будет работать:

$ grep -E 'COL|pattern' file.csv

Ответ 7

Итак, спустя некоторое время я опубликовал совершенно другой короткий ответ.

Однако для тех, кто ищет команду, которая выглядит как grep с точки зрения принятия всех одинаковых параметров (хотя этот script требует использования длинных опций, если задействован optarg), и может справляться со странными символами в имена файлов и т.д. и т.д., получайте удовольствие от этого.

По существу это grep, который всегда испускает первую строку. Если вы считаете, что файл без соответствующих строк не должен пропускать эту первую (заголовочную) строку, это значит, что в качестве упражнения для читателя. Я сохранил как grep+1.

#!/bin/bash
# grep+1 [<option>...] [<regex>] [<file>...]
# Emits the first line of each input and ignores it otherwise.
# For grep options that have optargs, only the --forms will work here.

declare -a files options
regex_seen=false
regex=

double_dash_seen=false
for arg in "[email protected]" ; do
    is_file_or_rx=true
    case "$arg" in
        -*) is_file_or_rx=$double_dash_seen ;;
    esac
    if $is_file_or_rx ; then
        if ! $regex_seen ; then
            regex="$arg"
            regex_seen=true
        else
            files[${#files[*]}]="$arg"     # append the value
        fi
    else
        options[${#options[*]}]="$arg"     # append the value       
    fi
done

# We could either open files all at once in the shell and pass the handles into
# one grep call, but that would limit how many we can process to the fd limit.
# So instead, here the simpler approach with a series of grep calls

if $regex_seen ; then
    if [ ${#files[@]} -gt 0 ] ; then
        for file in "${files[@]}" ; do
            head -n 1 "$file"
            tail -n +2 "$file" | grep --label="$file" "${options[@]}" "$regex" 
        done
    else
        grep "${options[@]}"   # stdin
    fi
else
    grep "${options[@]}"   # probably --help
fi

#--eof

Ответ 8

Все ответы были правильными. Просто еще одна идея для ситуаций, чтобы grep вывод команды (а не файла), включая первую строку, может быть сделано следующим образом ;-)

df -h | grep -E '(^Filesystem|/mnt)'  # <<< returns usage of devices, with mountpoint '/mnt/...'
ps aux | grep -E '(^USER|grep)'       # <<< returns all grep-process

Опция -E grep включает режим регулярных выражений. Строка, которую мы используем grep | и может интерпретироваться как "или", поэтому мы смотрим в файле df -E xmaple:

  • начиная с Filesystem (ведущий '^' в первом подвыражении означает "строка начинается с")
  • и строки, содержащие /mnt

Другой способ может заключаться в том, чтобы перенаправить вывод в tempfile файл и создать содержимое, как показано в других публикациях. Это может быть полезно, если вы не знаете содержание первой строки.

head -1 <file> && grep ff <file>

Ответ 9

Просто сделай

head -1 <filename> 

а затем выполните grep