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