Самый простой способ сделать это:
cat test.txt | perl -pe "s/^(#.*)/\e[0;32m\1\033[0m/g || s/(aaa|bbb)/\e[1;31m\1\033[0m/g"
Здесь используется логический оператор or ||
, чтобы указать perl запускать второй s///
только в том случае, если первый не выполнился. т.е. аналогично if (/#/) ... else if (/aaa|bbb/) ....
Вы можете добавить еще || s///
в конце скрипта, если это необходимо, но если вам нужно найти и раскрасить много совпадений, сделать это в виде одной строки будет слишком сложно. В таком случае перепишите все это как отдельный #! /usr/bin/perl -p
, возможно, с одним s///g ||
на строку, и завершающей точкой с запятой вместо ||
в последней строке.
Например:
#! /usr/bin/perl -p
s/^(#.*)/\e[0;32m\1\033[0m/g ||
s/(aaa|bbb)/\e[1;31m\1\033[0m/g ||
s/(ccc)/\e[1;34m\1\033[0m/g ;
Обратите внимание, что такой способ означает, что в любой заданной строке будет найдено только одно совпадение, и первое совпадение победит. Таким образом, в моем примере с длинным скриптом выше, если 'aaa' или 'bbb' будут найдены на строке, то они будут окрашены, но если 'ccc' будет на той же строке, то не будет.
Наконец, похоже, что вы заново изобретаете колесо. Уже существует несколько инструментов для выделения текста цветом. Например, инструмент highlight. Он в основном используется для подсветки синтаксиса исходного кода, но может быть использован для придания цвета любому виду текста.
Если команда, которую вы показываете в своем вопросе, в основном работает (для жесткого -закодированного количества файлов ), тогда
first=1
for f in file*.gz
do
if [ "$first" ]
then
gzcat "$f"
first=
else
gzcat "$f"| tail -n +2
fi
done > collection_single_file
должен работать на вас. Надеюсь, логика достаточно ясна. Просмотрите все файлы (и измените подстановочные знаки в соответствии с вашими именами файлов ). Если это первое в списке, gzcat
это, так что вы получите весь файл (включая заголовок ). В противном случае используйте tail
для удаления заголовка. После того, как вы обработаете файл, никакой другой файл не будет первым.
Это вызываетtail
N −1 раз, а не один раз (, как ваш ответ ). Кроме того, мой ответ должен работать так же, как ваш ответ.
Вариация G -Решение Мана , в котором не используется отдельная переменная для отслеживания первого файла:
set -- file*.gz
{
gzcat "$1"; shift
for file do
gzcat "$file" | sed '1d'
done
} >combined.txt
Это распаковывает первый файл, а затем перебирает остальные, пропуская каждый через короткий sed
скрипт, удаляющий первую строку. Вывод перенаправляется на combined.txt
.
Команда set -- file*.gz
устанавливает позиционные параметры ($1
, $2
и т. д., которые в совокупности представляют собой массив$@
)для имен файлов, соответствующих заданному шаблону. shift
удаляет $1
из массива после его распаковки. Цикл проходит по оставшимся именам файлов в массиве и также может быть записан
for file in "$@"; do
gzcat "$file" | sed '1d'
done
{... }
позволяет нам перенаправить вывод команд в файл за один раз.
Еще короче, с дополнительным предположением, что «строка заголовка» всегда начинается с символа #
(, как в примере в вопросе ), и что других таких строк в данных нет.:
gzcat file*.gz | awk 'NR > 1 && /^#/ { next } 1' >combined.txt
или,
gzcat file*.gz | sed '2,${ /^#/d; }' >combined.txt
Оба они пропускают любую строку, начинающуюся с #
, если она встречается во второй строке или позже в объединенном содержимом несжатых данных.