Cmd объединяет текстовые файлы и 13 инструментов обработки текстов в командной оболочке

Здесь представлен фрагмент будущей книги «Основные инструменты и практики для начинающего разработчика программного обеспечения» Бальтазара Рубероля и Этьена Броду
. Книга должна помочь образованию подрастающего поколения разработчиков. Она охватит такие темы, как освоение консоли, настройка и эффективная работа в командной оболочке, управление версиями кода с помощью git
, основы SQL, инструменты вроде Make
, jq
и регулярные выражения, основы сетевого взаимодействия, а также лучшие практики разработки программного обеспечения и совместной работы. В настоящее время авторы упорно работают над этим проектом и приглашают всех поучаствовать в списке рассылки
.

Cat

Команда cat
используется для составления списка из одного или нескольких файлов и отображения их содержимого на экране.

   $ cat Documents/readme
Thanks again for reading this book!
I hope you're following so far!

$ cat Documents/computers
Computers are not intelligent
They're just fast at making dumb things.

$ cat Documents/readme Documents/computers
Thanks again for reading this book!
I hope you are following so far!

Computers are not intelligent
They're just fast at making dumb things.  
  

Sort

Команда sort
, собственно, сортирует данные (в указанном файле или входном потоке).

   $ cat ingredients
eggs
milk
butter
tomatoes
salt
$ sort ingredients
butter
eggs
milk
salt
tomatoes  
  

sort -r
выполняет обратную сортировку.

   $ sort -r ingredients
tomatoes
salt
milk
eggs
butter  
  

sort -n
сортирует поля по их арифметическому значению.

   $ cat numbers
0
2
1
10
3
$ sort numbers
0
1
10
2
3
$ sort -n numbers
0
1
2
3
10  
  

Реальные примеры

Фильтрация CSV с помощью grep и awk

   $ grep -w gauge metadata.csv | awk -F, '{ if ($4 == "query") { print $1, "per", $5 } }'
mysql.performance.com_delete per second
mysql.performance.com_delete_multi per second
mysql.performance.com_insert per second
mysql.performance.com_insert_select per second
mysql.performance.com_replace_select per second
mysql.performance.com_select per second
mysql.performance.com_update per second
mysql.performance.com_update_multi per second
mysql.performance.questions per second
mysql.performance.slow_queries per second
mysql.performance.queries per second  
  

В этом примере grep
в файле metadata.csv
сначала фильтрует строки, содержащие слово gauge
, затем те, у которых query
в четвёртой колонке, и выводит название метрики (1-я колонка) с соответствующим значением per_unit_name
(5-я колонка).

Вывод адреса IPv4, связанного с сетевым интерфейсом

   $ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38  
  

Команда ifconfig <interface name>
выводит сведения по указанному сетевому интерфейсу. Например:

   en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether 19:64:92:de:20:ba
    inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
    inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active  
  

Затем запускаем grep
для inet
, что выдаст две строки соответствия.

   $ ifconfig en0 | grep inet
    inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
    inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255  
  

Затем с помощью grep -v
исключаем строку с ipv6
.

   $ ifconfig en0 | grep inet | grep -v inet6
inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255  
  

Наконец, с помощью awk
запрашиваем второй столбец в этой строке: это IPv4-адрес, связанный с нашим сетевым интерфейсом en0
.

   $ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38  
  

Примечание. Мне предложили
заменить grep inet | grep -v inet6
такой надёжной командой awk
:

   $ ifconfig en0 | awk ' $1 == "inet" { print $2 }'
192.168.0.38  
  

Она короче и конкретно нацелена на IPv4 с условием $1 == "inet"
.

Извлечение значения из файла конфигурации

   $ grep 'editor =' ~/.gitconfig  | cut -d = -f2 | sed 's/ //g'
/usr/bin/vim  
  

В файле конфигурации git текущего пользователя ищем значение editor =
, обрезаем знак =
, извлекаем второй столбец и удаляем все пробелы вокруг.

   $ grep 'editor =' ~/.gitconfig
     editor = /usr/bin/vim
$ grep 'editor =' ~/.gitconfig  | cut -d'=' -f2
 /usr/bin/vim
$ grep 'editor =' ~/.gitconfig  | cut -d'=' -f2 | sed 's/ //'
/usr/bin/vim  
  

Извлечение IP-адресов из файла журнала

   $ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -n 10 | \
  awk '{ print $2 }'
   10.11.112.108
   10.11.111.70
   10.11.97.57
   10.11.109.72
   10.11.116.156
   10.11.100.221
   10.11.96.242
   10.11.81.68
   10.11.99.112
   10.11.107.120  
  

Давайте разберем, что делает этот конвейер. Во-первых, как выглядит строка в журнале.

   $ grep "Too many connections from" db.log | head -n 1
2020-01-01 08:02:37,617 [myid:1] - WARN  [NIOServerCxn.Factory:1.2.3.4/1.2.3.4:2181:NIOServerCnxnFactory@193] - Too many connections from /10.11.112.108 - max is 60  
  
   $ grep "Too many connections from" db.log | awk '{ print $12 }'
/10.11.112.108
...  
  
   $ grep "Too many connections from" db.log | awk '{ print $12 }' | sed 's@/@@'
10.11.112.108
...  
  

Примечание. Как мы уже видели ранее, в sed
можно использовать любой разделитель. Хотя обычно в качестве разделителя используется /
, здесь мы заменяем именно этот символ, что слегка ухудшит читаемость выражения подстановки.

   sed 's/\///'  
  
   $ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c
   1379 10.11.100.221
   1213 10.11.103.168
   1138 10.11.105.177
    946 10.11.106.213
   1211 10.11.106.4
   1326 10.11.107.120
   ...  
  
   $ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -n 10 | \
  awk '{ print $2 }'
  10.11.112.108
  10.11.111.70
  10.11.97.57
  10.11.109.72
  10.11.116.156
  10.11.100.221
  10.11.96.242
  10.11.81.68
  10.11.99.112
  10.11.107.120  
  

Переименование функции в исходном файле

Представим, что мы работаем над проектом и хотели бы переименовать недачно названную функцию (или класс, переменную и т. д.) в исходном файле. Можно сделать это с помощью команды sed -i
, которая выполняет замену прямо в оригинальном файле.

   $ cat izk/utils.py
def bool_from_str(s):
    if s.isdigit():
        return int(s) == 1
    return s.lower() in ['yes', 'true', 'y']  
  

   $ sed -i 's/def bool_from_str/def is_affirmative/' izk/utils.py
$ cat izk/utils.py
def is_affirmative(s):
    if s.isdigit():
        return int(s) == 1
    return s.lower() in ['yes', 'true', 'y']  
  

Примечание. На macOS вместо sed -i
используйте sed -i ''
.

Однако мы переименовали функцию только в оригинальном файле. Это сломает импорт bool_from_str
в любом другом файле, поскольку эта функция больше не определена. Нужно найти способ переименовать bool_from_str
повсюду в нашем проекте. Такого можно добиться с помощью команд grep
, sed
, а также циклов for
или с помощью xargs
.

Awk

awk
— это чуть больше, чем просто инструмент обработки текста: на самом деле у него целый язык программирования
. В чём awk
действительно
хорош — так это в разбиении файлов на столбцы, и делает это с особенным блеском, когда в файлах перемешаны пробелы и табы.

   $ cat -t multi-columns
John Smith    Doctor^ITardis
Sarah-James Smith^I    Companion^ILondon
Rose Tyler   Companion^ILondon  
  

Примечание. cat -t
отображает табы как ^I
.

Как видим, столбцы разделены либо пробелами, либо табуляциями, и не всегда одинаковым количеством пробелов. cut
здесь бесполезен, потому что работает только с одним символом-разделителем. Но awk
легко разберётся с таким файлом.

   $ cat multi-columns | awk '{ print $1 }'
John
Sarah-James
Rose
$ cat multi-columns | awk '{ print $3 }'
Doctor
Companion
Companion
$ cat multi-columns | awk '{ print $1,$2 }'
John Smith
Sarah-James Smith
Rose Tyler  
  

Хотя awk
способен на гораздо большее, выдача колонок составляет, наверное, 99% вариантов использования в моём личном случае.

Примечание. { print $NF }
выводит последний столбец в строке.

Uniq

uniq
обнаруживает и отфильтровывает соседние одинаковые строки в указанном файле или входном потоке.

   $ cat duplicates
and one
and one
and two
and one
and two
and one, two, three
$ uniq duplicates
and one
and two
and one
and two
and one, two, three  
  

Поскольку uniq
отфильтровывает только соседние
строки, в наших данных могут ещё остаться дубликаты. Чтобы отфильтровать все одинаковые строки из файла, нужно сначала отсортировать его содержимое.

   $ sort duplicates | uniq
and one
and one, two, three
and two  
  

uniq -c
в начале каждой строки вставляет количество её вхождений.

   $ sort duplicates | uniq -c
   3 and one
   1 and one, two, three
   2 and two  
  

uniq -u
отображает только уникальные строки.

   $ sort duplicates | uniq -u
and one, two, three  
  

Примечание. uniq
особенно полезен в сочетании с сортировкой, поскольку конвейер | sort | uniq
позволяет удалить все дублирующиеся строки в файле или потоке.

Fold

Команда fold
сворачивает все входные строки до заданной ширины. Например, может быть полезно убедиться, что текст помещается на дисплеях небольшого размера. Так, fold -w n
укладывает строки по ширине n символов.

   $ cat ~/Documents/readme | fold -w 16
Thanks again for
 reading this bo
ok!
I hope you're fo
llowing so far!  
  

Команда fold -s
будет разбивать строки только на символах пробела. Её можно объединить с предыдущей, чтобы ограничить строким заданным количеством символом.

   Thanks again
for reading
this book!
I hope you're
following so
far!  
  

Head

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

   $ head -n 2 metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
mysql.galera.wsrep_cluster_size,gauge,,node,,The current number of nodes in the Galera cluster.,0,mysql,galera cluster size  
  

Если -n
не указано, head
выводит первые десять строк указанного файла или входящего потока.

:/>  Не работает левая или правая кнопка мыши (ЛКМ

Grep

grep
— это швейцарский нож фильтрации строк по заданному шаблону.

Например, можем найти все вхождения слова mutex
в файле.

   $ grep mutex metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.mutex_spin_rounds,gauge,,event,second,The rate of mutex spin rounds.,0,mysql,mutex spin rounds
mysql.innodb.mutex_spin_waits,gauge,,event,second,The rate of mutex spin waits.,0,mysql,mutex spin waits  
  

grep
может обрабатывать либо файлы, указанные в качестве аргументов, либо поток текста, переданный на его stdin
. Таким образом, мы можем сцеплять несколько команд grep
для дальнейшей фильтрации текста. В следующем примере мы фильтруем строки в нашем файле metadata.csv
, чтобы найти строки, содержащие и mutex
, и OS
.

   $ grep mutex metadata.csv | grep OS
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits  
  

Рассмотрим некоторые опции grep
и их поведение.

grep -v
выполняет инвертное сопоставление: фильтрует строки, которые не
соответствуют шаблону аргументов.

   $ grep -v gauge metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name  
  

grep -i
выполняет сопоставление без учёта регистра. В следующем примере grep -i os
находит как OS
, так и os
.

   $ grep -i os metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.os_log_fsyncs,gauge,,write,second,The rate of fsync writes to the log file.,0,mysql,log fsyncs  
  

grep -l
выводит список файлов, содержащих совпадение.

   $ grep -l mysql metadata.csv
metadata.csv  
  

Команда grep -c
подсчитывает, сколько раз найден образец.

   $ grep -c select metadata.csv
3  
  

grep -r
рекурсивно ищет файлы в текущем рабочем каталоге и всех его подкаталогах.

   $ grep -r are ~/Documents
/home/br/Documents/computers:Computers are not intelligent
/home/br/Documents/readme:I hope you are following so far!  
  

grep -w
показывает только совпадающие целиком слова.

   $ grep follow ~/Documents/readme
I hope you are following so far!
$ grep -w follow ~/Documents/readme
$  
  

wc
(word count) выводит количество символов ( -c
), слов ( -w
) или строк ( -l
) в указанном файле или потоке.

   $ wc -l metadata.csv
43  metadata.csv
$ wc -w metadata.csv
405 metadata.csv
$ wc -c metadata.csv
5094 metadata.csv  
  

По умолчанию отображается всё вышеперечисленное.

   $ wc metadata.csv
43     405    5094 metadata.csv  
  

Если текстовые данные передаются по конвейеру или перенаправлены в stdin
, то отображается только счётчик.

   $ cat metadata.csv | wc
43     405    5094
$ cat metadata.csv | wc -l
43
$ wc -w < metadata.csv
405  
  

Sed

sed
— это неинтерактивный потоковый редактор, который используется для преобразования текста во входном потоке строка за строкой. В качестве входных данных используется или файл, или stdin
, а на выходе тоже или файл, или stdout
.

Команды редактора могут включать один или несколько адресов
, функцию
и параметры
. Таким образом, команды выглядят следующим образом:

   [address[,address]]function[arguments]  
  

Хотя sed
выполняет множество функций, мы рассмотрим только замену текста как один из самых распространённых вариантов использования.

Замена текста

Команда замены sed
выглядит следующим образом:

   s/PATTERN/REPLACEMENT/[options]  
  

Пример
: замена первого экземпляра слова в каждой строке в файле:

   $ cat hello
hello hello
hello world!
hi
$ cat hello | sed 's/hello/Hey I just met you/'
Hey I just met you hello
Hey I just met you world
hi  
  

Мы видим, что в первой строчке заменяется только первый экземпляр hello
. Чтобы заменить все
вхождения hello
во всех строках, можно использовать опцию g
(означает global
).

   $ cat hello | sed 's/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi  
  

sed
позволяет использовать любые разделители, кроме /
, что особенно улучшает читаемость, если в самих аргументах команды есть слэши.

   $ cat hello | sed 's@hello@Hey I just met you@g'
Hey I just met you Hey I just met you
Hey I just met you world
hi  
  

Адрес говорит редактору, в какой строке или диапазоне строк выполнять подстановку.

   $ cat hello | sed '1s/hello/Hey I just met you/g'
Hey I just met you hello
hello world
hi
$ cat hello | sed '2s/hello/Hey I just met you/g'
hello hello
Hey I just met you  world
hi  
  

Адрес 1
указывает заменять hello
на Hey I just met you
в первой строке. Можем указать диапазон адресов в нотации <start>,<end>
, где <end>
может быть либо номером строки, либо $
, то есть последней строкой в файле.

   $ cat hello | sed '1,2s/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi
$ cat hello | sed '2,3s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi
$ cat hello | sed '2,$s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi  
  

По умолчанию sed
выдаёт результат в свой stdout
, но может отредактировать и оригинальный файл с опцией -i
.

   $ sed -i '' 's/hello/Bonjour/' sed-data
$ cat sed-data
Bonjour hello
Bonjour world
hi  
  

Примечание. В Linux достаточно только -i
. Но в macOS поведение команды немного отличается, поэтому сразу после -i
нужно добавить ''
.

Что дальше

  1. Подсчитайте количество файлов и каталогов, расположенных в вашем домашнем каталоге.
  2. Отобразите содержимое файла только прописными буквами.
  3. Подсчитайте, сколько раз встречалось каждое слово в файле.
  4. Подсчитайте количество гласных в файле. Отсортируйте результат от наиболее распространённой до наименее распространённой буквы.
:/>  ✅ Служба управления ключами kms недоступна Windows 7 -


Будущая книга «Основные инструменты и практики для начинающего разработчика программного обеспечения» (Essential Tools and Practices for the Aspiring Software Developer) Бальтазара Рубероля и Этьена Броду
поможет создать продуктивную среду разработки и познакомиться с полезными инструментами и практиками, которые нужны для профессионального роста. Как уже было сказано, она охватит такие темы, как освоение терминала, настройка и эффективная работа в командной оболочке, управление версиями кода с помощью git
, основы SQL, инструменты вроде Make
, jq
и регулярные выражения, основы сетевого взаимодействия, а также лучшие практики разработки программного обеспечения и совместной работы.

tr
расшифровывается как translate
. Эта команда заменяет одни символы на другие. Она работает либо с символами, либо с классами
символов, такими как строчные, печатные, пробелы, буквенно-цифровые и т. д.

На стандартных входных данных tr <char1> <char2>
заменяет все вхождения <char1> на <char2>

   $ echo "Computers are fast" | tr a A
computers Are fAst  
  
   $ echo "computers are fast" | tr '[:space:]' ','
computers,are,fast,%  
  

Все символы, похожие на пробелы, переведены в запятую. Обратите внимание, что символ %
в конце выдачи означает отсутствие завершающей новой строки. Действительно, этот символ тоже переведён в запятую.

   $ echo "computers are fast" | tr '[:lower:]' '[:upper:]'
COMPUTERS ARE FAST
$ echo "COMPUTERS ARE FAST" | tr '[:upper:]' '[:lower:]'
computers are fast  
  

tr -c SET1 SET2
преобразует любой символ, не
входящий в набор SET1, в символы набора SET2. В следующем примере все символы, кроме указанных гласных, заменяются пробелами.

   $ echo "computers are fast" | tr -c '[aeiouy]' ' '
 o  u e   a e  a  
  

tr -d
удаляет указанные символы, а не заменяет их. Это эквивалент tr <char> ''
.

   $ echo "Computers Are Fast" | tr -d '[:lower:]'
C A F  
  

tr
также может заменить диапазоны символов, например, все буквы между a
и e
или все числа между 1 и 8, используя нотацию s-e
, где s
 — начальный символ, а e
 — конечный.

   $ echo "computers are fast" | tr 'a-e' 'x'
xomputxrs xrx fxst
$ echo "5uch l337 5p34k" | tr '1-4' 'x'
5uch lxx7 5pxxk  
  

Команда tr -s string1
сжимает все множественные вхождения символов в string1
в одно-единственное. Одним из наиболее полезных применений tr -s
является замена нескольких последовательных пробелов одним.

   $ echo "Computers         are       fast" | tr -s ' '
Computers are fast  
  

Обработка текста в командной оболочке

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

При работе с текстовыми данными главный принцип заключается в том, чтобы разбить любую сложную проблему на множество более мелких — и решить каждую из них с помощью специализированного инструмента.

Заставьте каждую программу хорошо выполнять одну функцию — «Основы философии Unix»

Примеры из этой главы на первый взгляд могут показаться немного надуманными, но это сделано специально. Каждый из инструментов разработан для решения одной небольшой задачи. Однако в сочетании они становятся чрезвычайно мощными.

Мы рассмотрим некоторые из наиболее распространенных и полезных команд обработки текста в командной оболочке и продемонстрируем реальные рабочие процессы, соединяющие их вместе. Я предлагаю взглянуть на маны этих команд, чтобы увидеть всю широту возможностей в вашем распоряжении.

Файл CSV с примерами доступен в онлайне
. Можете скачать его для проверки материала.

Cut

cut
извлекает часть файла (или, как обычно, входного потока). Команда определяет разделитель полей (который разделяет столбцы) с помощью опции -d
, а порядковые номера столбцов для извлечения с помощью опции -f
.

Например, следующая команда извлекает первый столбец из последних пяти строк нашего CSV-файла.

   $ tail -n 5 metadata.csv | cut -d , -f 1
mysql.performance.user_time
mysql.replication.seconds_behind_master
mysql.replication.slave_running
mysql.replication.slaves_connected
mysql.performance.queries  
  

Поскольку мы имеем дело с CSV, то столбцы разделяются запятой, а за извлечение первого столбца отвечает опция -f 1
.

Можно выбрать и первый, и второй столбцы, используя опцию -f 1,2
.

   $ tail -n 5 metadata.csv | cut -d , -f 1,2
mysql.performance.user_time,gauge
mysql.replication.seconds_behind_master,gauge
mysql.replication.slave_running,gauge
mysql.replication.slaves_connected,gauge
mysql.performance.queries,gauge  
  

Циклы for и xargs

Чтобы заменить в нашем проекте все вхождения bool_from_str
, сначала нужно рекурсивно найти их с помощью grep -r
.

   $ grep -r bool_from_str .
./tests/test_utils.py:from izk.utils import bool_from_str
./tests/test_utils.py:def test_bool_from_str(s, expected):
./tests/test_utils.py:    assert bool_from_str(s) == expected
./izk/utils.py:def bool_from_str(s):
./izk/prompt.py:from .utils import bool_from_str
./izk/prompt.py:                    default = bool_from_str(os.environ[envvar])  
  

Поскольку нас интересуют только файлы c совпадениями, также необходимо использовать опцию -l/--files-with-matches
:

   -l, --files-with-matches
        Only the names of files containing selected lines are written to standard out-
        put.  grep will only search a file until a match has been found, making
        searches potentially less expensive.  Pathnames are listed once per file
        searched.  If the standard input is searched, the string ``(standard input)''
        is written.  
  

   $ grep -r --files-with-matches bool_from_str .
./tests/test_utils.py
./izk/utils.py
./izk/prompt.py  
  

Затем можем использовать команду xargs
для осуществления действий с каждой строки выходных данных (то есть всех файлов, содержащих строку bool_from_str
).

   $ grep -r --files-with-matches bool_from_str . | \
  xargs -n 1 sed -i 's/bool_from_str/is_affirmative/'  
  

Опция -n 1
указывает, что каждая строка в выходных данных должна выполнить отдельную команду sed
.

Затем выполняются следующие команды:

   $ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py  
  

Если команда, которую вы вызываете с помощью xargs
(в нашем случае sed
), поддерживает несколько аргументов, то следует отбросить аргумент -n 1
для производительности.

   grep -r --files-with-matches bool_from_str . | xargs sed -i 's/bool_from_str/is_affirmative/'  
  

Эта команда затем исполнит

   $ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py ./izk/utils.py ./izk/prompt.py  
  

Примечание. Из синопсиса sed
на ман-странице видно, что команда может принять несколько аргументов.

   SYNOPSIS
     sed [-Ealn] command [file ...]
     sed [-Ealn] [-e command] [-f command_file] [-i extension] [file ...]  
  

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

Мы видим, что произведены замены для всех вхождений bool_from_str
.

   $ grep -r is_affirmative .
./tests/test_utils.py:from izk.utils import is_affirmative
./tests/test_utils.py:def test_is_affirmative(s, expected):
./tests/test_utils.py:    assert is_affirmative(s) == expected
./izk/utils.py:def is_affirmative(s):
./izk/prompt.py:from .utils import is_affirmative
./izk/prompt.py:                    default = is_affirmative(os.environ[envvar])  
  

Как это часто бывает, существует несколько способов достижения одного и того же результата. Вместо xargs
мы могли бы использовать циклы for
, чтобы перебирать строки по списку и выполнять действие над каждым элементом. У этих циклов такой синтаксис:

   for item in list; do
    command $item
done  
  

Если обернуть нашу команду grep
в $()
, то оболочка выполнит её в подоболочке
, результат чего затем будет повторён в цикле for
.

   $ for file in $(grep -r --files-with-matches bool_from_str .); do
  sed -i 's/bool_from_str/is_affirmative/' $file
done  
  

Эта команда выполнит

   $ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py  
  

Синтаксис циклов for
кажется мне более чётким, чем у xargs
, однако последняя может выполнять команды параллельно, используя параметры -P n
, где n
— максимальное количество параллельных команд, выполняемых одновременно, что может дать выигрыш в производительности.

:/>  ✅ Служба управления ключами kms недоступна Windows 7 -

Paste

paste
объединяет вместе два разных файла в один многоколоночный файл.

   $ cat ingredients
eggs
milk
butter
tomatoes
$ cat prices
1$
1.99$
1.50$
2$/kg
$ paste ingredients prices
eggs    1$
milk    1.99$
butter  1.50$
tomatoes    2$/kg  
  

По умолчанию paste
использует разделитель табуляции, но его можно изменить с помощью параметра -d
.

   $ paste ingredients prices -d:
eggs:1$
milk:1.99$
butter:1.50$
tomatoes:2$/kg  
  

Ещё один распространённый способ использования paste
 — объединение всех строк в потоке или файле с помощью заданного разделителя, используя комбинацию аргументов -s
и -d
.

   $ paste -s -d, ingredients
eggs,milk,butter,tomatoes  
  

Если в качестве входного файла указан параметр -
, то вместо него будет считываться stdin
.

   $ cat ingredients | paste -s -d, -
eggs,milk,butter,tomatoes  
  

Tail

tail
— аналог head
, только он выводит последние n строк в файле.

   $ tail -n 1 metadata.csv
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries  
  

Если хотите вывести все строки, расположенном после n-й строки (включая её), можете использовать аргумент -n +n
.

   $ tail -n +42 metadata.csv
mysql.replication.slaves_connected,gauge,,,,Number of slaves connected to a replication master.,0,mysql,slaves connected
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries  
  

В нашем файле 43 строки, поэтому tail -n +42
выводит только 42-ю и 43-ю строки из него.

Если параметр -n
не указан, tail
выведет последние десять строк в указанном файле или входном потоке.

Резюме

Все эти инструменты открывают целый мир возможностей, так как позволяют извлекать и преобразовывать данные, создавая целые конвейеры из команд, которые, возможно, никогда не предназначались для совместной работы. Каждая из них выполняет относительно небольшую функцию (сортировка sort
, объединение cat
, фильтры grep
, редактирование sed
, вырезание cut
и т. д.).

Любую задачу, включающую текст, можно свести к конвейеру более мелких задач, каждая из которых выполняет простое действие и передаёт свои выходные данные в следующую задачу.

  • grep
    строк, которые соответствуют шаблону строк с IP-адресами

  • найти столбец с IP-адресом, извлечь его с помощью awk

  • отсортировать список IP-адресов с помощью sort

  • устранить смежные дубликаты с помощью uniq

  • подсчитать количество строк (то есть уникальных IP-адресов) с помощью wc -l

Поскольку есть множество нативных и сторонних инструментов обработки текста, также много способов решить любую задачу.

Примеры в этой статье были надуманными, но я предлагаю вам прочитать удивительную статью «Инструменты командной строки могут быть в 235 раз быстрее, чем ваш кластер Hadoop»
, чтобы получить представление о том, насколько полезны и мощны эти команды на самом деле и какие реальные проблемы они могут решить.

Оставьте комментарий