вступление
Работа с интерфейсом командной строки, как правило, является очень самоуверенной средой. У каждого есть свои предпочтительные инструменты. Рабочий процесс у всех немного отличается в зависимости от личных предпочтений, задач, которые они регулярно выполняют, и даже культуры на рабочем месте. Но независимо от предпочтений, культуры или повседневных задач некоторые вещи остаются общими.
Обзор использования CLI
При использовании CLI вы всегда работаете с текстом и всегда хотите, чтобы это было максимально удобно. Есть также общие сценарии, с которыми вы имеете дело на регулярной основе. В целом вы можете объединить эти сценарии с работой с форматированными документами (код, LaTeX, JSON, и т. д.), с журналами и взаимодействием с оболочкой. Следует признать, что между первыми двумя сценариями есть совпадение, то есть, журналы, безусловно, отформатированы, а некоторые записываются в JSON, но мы взаимодействуем с журналами иначе, чем с другими форматированными документами; с журналами мы извлекаем информацию, и это последнее, что мы хотим редактировать, с форматированными документами редактирование почти всегда связано.
Когда мы взаимодействуем с CLI, мы имеем дело со средой последовательного выполнения, которая включает в себя блокирующие действия. Если вы выполните что-то вроде tail, то, если вы не сделаете что-то, что мешает, это взаимодействие с оболочкой теперь заблокировано. То же самое в основном верно, когда вы запускаете любой исполняемый файл. Пока этот исполняемый файл не завершится, вы не сможете взаимодействовать с этим сеансом оболочки. Это означает, что для эффективной работы вам действительно нужен способ одновременной работы с несколькими интерактивными оболочками, будь то открытие нескольких терминалов, использование эмулятора с функцией вкладок, tmux/screen и т. д.
Работа с блокирующим интерфейсом
Мой любимый инструмент для управления несколькими интерактивными оболочками — tmux. Это то, что довольно быстро становится довольно самоуверенным, поэтому позвольте мне изложить причины его использования.
Во-первых, хотя tmux — довольно новый инструмент с точки зрения инструментов *nix, его популярность за последние 15 лет выросла настолько, что если он не предустановлен, то его легко установить с помощью любого доступного менеджера пакетов. Во-вторых, хотя он чрезвычайно настраиваемый, его также можно использовать из коробки. Ванильная установка дает мне возможность управлять несколькими сеансами оболочки, группировать экраны вместе, выбирать предыдущие сеансы оболочки с того места, где я остановился, и многое другое.
Я предпочитаю это использовать эмуляторы с поддержкой вкладок, потому что у меня почти всегда будет к нему доступ, тогда как настройка iTerm2 для удовлетворения моих потребностей означает, что мой рабочий процесс будет неудобным на чем-либо, кроме Mac.
Я также не полагаюсь на создание нового терминала для каждой нужной мне сессии, потому что это неудобно организовывать, а если у меня нет графического интерфейса, я все равно не могу создать еще один терминал. Подумайте, войдите в виртуальную машину Linux в облачном провайдере, таком как GCP или AWS. Вы можете либо использовать браузер для ssh входа в сеанс терминала, либо просто ssh со своего локального компьютера в сеанс терминала. Если у вас нет мультиплексора, вам придется создавать новый эмулятор для каждой нужной вам сессии.
Независимо от того, как вы решите проблему работы с блокирующим интерфейсом, будь то tmux, iTerm2, экран или что-то совсем другое, с этим вам придется бороться.
Взаимодействие с оболочкой
Для целей этой статьи я не буду вдаваться в то, какую оболочку вы должны выбрать, поскольку, опять же, это очень самоуверенная тема. Мой выбор оболочки менялся с годами по мере развития моего рабочего процесса, потребностей и желаний. Кроме того, можно привести хороший аргумент в пользу использования любой оболочки, которую я могу придумать, за исключением оболочек Thompson или Mashey, которые называются sh. Если вы не работаете с Ancient Unix, вы никогда с ними не столкнетесь.
Наиболее распространенные и полезные инструменты, используемые при работе с командной строкой, следуют философии UNIX. Любите вы это или ненавидите, но к этому обсуждению имеет отношение то, что любой достойный инструмент будет предполагать, что его выходные данные будут входными данными для другого инструмента, о котором он ничего не знает. Другими словами, подавляющее большинство инструментов будут использовать конвейеры для связывания нескольких команд вместе, чтобы делать новые вещи.
Например, если я хочу увидеть все строки, содержащие слово «ошибка», я могу сделать tail file.log | grep error, а если файл журнала активен, я могу сделать tail -f file.log | grep error, при этом строки журнала будут отображаться только в том случае, если они содержат слово «ошибка».
Приведенные выше примеры явно упрощены и, возможно, немного надуманы, но дело в том, что в вашем распоряжении будет множество инструментов, и почти все они могут быть соединены вместе, чтобы добиться гораздо большего, чем любой из них. Это лего, научитесь складывать их вместе, и вы сэкономите себе много времени и сил. Давайте посмотрим на пример, который немного более «реален».
Если вы вообще работаете с REST API, вы, вероятно, знакомы с cURL, который используется для отправки HTTP-запроса и отображения ответа. Распространенным шаблоном для команды PUT является возврат полезной нагрузки JSON. Неформатированный JSON уродлив и труден для чтения. Мы также хотим поиграть с OpenAI, потому что сейчас это модно. Сначала давайте отправим команду curl, чтобы мы могли убедиться, что ответ соответствует нашим ожиданиям:
curl https://api.openai.com/v1/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"model": "text-davinci-003", "prompt": "Say this is a test", "temperature": 0, "max_tokens": 7}'
Это вернуло этот уродливый кусок JSON:
{"id":"cmpl-6SXlLQAk9smbBI2TuNjNCEdKH6FHW","object":"text_completion","created":1672260987,"model":"text-davinci-003","choices":[{"text":"\n\nThis is indeed a test","index":0,"logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":5,"completion_tokens":7,"total_tokens":12}}
Давайте передадим это в jq, чтобы красиво напечатать:
curl https://api.openai.com/v1/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 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" \
-d '{"model": "text-davinci-003", "prompt": "Say this is a test", "temperature": 0, "max_tokens": 7}' | jq '.'
Что дает гораздо более удобочитаемую версию, показанную ниже:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 383 100 287 100 96 318 106 --:--:-- --:--:-- --:--:-- 425
{
"id": "cmpl-6SXtWoZY29vj2hIK2PqdsvIe1jUoc",
"object": "text_completion",
"created": 1672261494,
"model": "text-davinci-003",
"choices": [
{
"text": "\n\nThis is indeed a test",
"index": 0,
"logprobs": null,
"finish_reason": "length"
}
],
"usage": {
"prompt_tokens": 5,
"completion_tokens": 7,
"total_tokens": 12
}
}
Добавив один простой инструмент, мы сделали возможным чтение возвращенного JSON. В дополнение к каналам, перенаправления — еще один инструмент, облегчающий вашу жизнь. Перенаправление позволяет отправлять вывод из STDOUT, который по умолчанию является экраном, в файл. Одиночный символ перенаправления (>) создаст новый файл, если он не существует, или перезапишет существующий файл, если он существует. Используя два символа перенаправления, >> будет добавляться к существующему файлу, а не перезаписываться. Теперь я могу просто добавить >> sample_response.json после команды jq, и результаты JSON будут в файле, готовом к использованию в редакторе.
Существует больше инструментов, чем вы можете сосчитать, и все они могут быть использованы в качестве строительных блоков для создания результатов, полезность и сила которых ограничены только вашей готовностью понять и использовать их.
Работа с журналами
Когда дело доходит до работы с журналами, мы обычно пытаемся каким-либо образом найти определенные части журнала, например,, время, период, определенный тип сообщения, определенный идентификатор ( номер клиента, идентификатор услуги и т. д. и т. д. ), а также некоторые комбинированные факторы, подобные перечисленным выше.
Другая распространенная возможность заключается в том, что мы можем собирать журналы для обнаружения тенденций. Например, может быть, мы ищем несанкционированные попытки входа в систему за последний час или хотим узнать, сколько тайм-аутов подключения произошло в определенной службе за последние две недели.
Теперь очевидно, что аналитика и мониторинг могут выполняться гораздо эффективнее в производственной среде, если мы используем инструменты и службы, специально созданные для этих целей, такие как Grafana, Prometheus, Datadog и т. д., и т. д., но бывают случаи, когда просто проще проводить исследования с необработанными журналами с помощью специальных инструментов. Иногда необработанные журналы являются единственным источником данных, необходимых для вашего расследования.
Журналы (по крайней мере, хорошие) будут иметь согласованный формат. Многие журналы смоделированы на основе формата журнала Linux, который по умолчанию выглядит следующим образом:
приоритет, отметка времени, имя хоста, имя службы, сообщение
Ниже приведен фрагмент журнала, выводимого sshd, когда происходит попытка входа в систему, а пользователь не существует. Обратите внимание, что в этом случае приоритет не регистрируется. Кроме того, вы обнаружите, что во многих журналах отсутствует приоритет в сообщениях журнала. Более подробную информацию вы можете найти здесь.
Jul 7 10:51:24 chaves sshd[19537]: Invalid user admin from spongebob.lab.ossec.net
Существует ряд распространенных инструментов CLI, которые можно использовать для облегчения изучения журналов.
Группа:
Я думаю, что первый инструмент, который приходит на ум большинству людей, это grep. Grep предоставляет гибкие и мощные возможности поиска. Ключ, необходимый для разблокировки этой силы, — это регулярные выражения или RegEx. Сила Grep заключается в его способности применять шаблоны регулярных выражений к поиску. Я бы также порекомендовал использовать флаг -E вместо -e, чтобы предотвратить множество дополнительных экранов обратной косой черты, которые будут более подвержены ошибкам, а также труднее читать. Например, приведенная ниже команда будет искать в файле системного журнала любую запись, содержащую текст system76, независимо от того, что идет до или после него, при условии, что за текстом следует двоеточие и пробел ( “:“). Он также напечатает номер строки, в которой он нашел ссылку.
grep -n -E ".*system76.*: .*" /var/log/syslog
Полную информацию о регулярном выражении, которое он понимает, и все флаги команд можно найти здесь.
Голова и хвост:
Если вам просто нужно быстро заглянуть в начало или конец журнала, скажем, чтобы убедиться, что он начал или остановил выполнение без ошибок, то вы найдете полезные команды head и tail. Они просто отображают первые N или последние N строк файла. Есть удобный флаг, который указывает tail продолжать вывод любых данных, добавляемых к файлу по мере его роста. Это чрезвычайно полезно в среде разработки. Вы можете взглянуть на справочные страницы для них, чтобы получить полную информацию.
Ок и вырезать:
Поскольку все полезные журналы следуют определенному согласованному формату, мы можем использовать awk, чтобы анализировать их для получения конкретной информации. Хотя Awk представляет собой собственный язык обработки текста и выходит далеко за рамки этой статьи, он может быть очень полезным инструментом для работы с любым документом, имеющим согласованное форматирование, а не только с журналами. Awk — еще один инструмент, для эффективного использования которого требуется хотя бы минимальное знание регулярных выражений. Возвращаясь к нашему предыдущему примеру журнала:
Jul 7 10:51:24 chaves sshd[19537]: Invalid user admin from spongebob.lab.ossec.net
Следующая команда найдет строку с помощью регулярного выражения и напечатает имя пользователя и имя хоста, с которого был отправлен неудачный запрос. Обратите внимание, что запятая между двумя полями необходима для разделения вывода:
awk "/.*Invalid user.*/ { print $8, $10}" /var/log/auth.log
Утилита cut используется для выбора текста с разделителями и вывода его на стандартный вывод. Обратите внимание, что, несмотря на свое название, он не изменяет текст исходного файла.
Используя cut, вы можете выделить текст по символу или позиции байта (или диапазону), а также по полю, используя произвольный разделитель. Например, нам нужен список всех учетных записей, которые в настоящее время находятся на машине, для аудита безопасности. Мы знаем, что можем найти окончательный список учетных записей для машины в /etc/passwd. Допустим, наш файл выглядит так:
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
Если мы хотим создать файл со списком всех учетных записей, созданных на машине, мы можем сделать что-то вроде этого, которое выбирает первое поле из файла, используя двоеточие (:) в качестве разделителя, и записывает результат в файл. называется account-list.txt:
cut -d ':' -f 1 /etc/passwd > account-list.txt
В результате получится файл, содержащий следующее:
root daemon bin sys sync games man lp mail news uucp proxy
Существует много информации для обеих этих команд, но вот справочная страница для awk и cut, чтобы вы могли начать.
Работа с форматированными документами
Я оставил это напоследок, потому что это и очень простая, и очень сложная тема. Хотя все упомянутые ранее инструменты, безусловно, можно использовать для работы с форматированными документами, существуют инструменты, разработанные специально для редактирования текста.
Сед:
Sed — это потоковый редактор, который позволяет выполнять операции вставки, удаления и замены на основе выделенного текста. Быстрый пример использования ввода из /etc/passwd, используемого в приведенной выше команде cut, может состоять в том, чтобы пометить все учетные записи служб, поскольку мы знаем, что все учетные записи, которые имеют /user/sbin/nologin вместо начальной оболочки, будут учетными записями служб.
Слово предостережения здесь; сейчас мы приступаем к редактированию, что может быть опасно, если вы говорите о системных файлах, таких как /etc/passwd, поэтому я рекомендую всегда использовать флаг -i при использовании sed в системных документах. флаг -i позволяет указать создание резервной копии перед любым редактированием. Еще лучше, не редактируйте системные файлы напрямую, просто создайте дубликат и внесите в него свои изменения. Затем в любом случае сделайте резервную копию оригинала на случай, если что-то сломается, когда вы начнете использовать новый.
В приведенном ниже примере создается резервная копия исходного файла с именем passwd.backup, считывается содержимое исходного файла, заменяется пробел между первым и последним разделителями (:) и заменяется /usr/sbin/nologin текстом Учетная запись службы.
sed -i'.backup' -e 's/:.*:/ /g' -e 's/\/usr\/sbin\/nologin/ Service account/g' cut-test.txt
После выполнения этой команды файл будет выглядеть так:
root /bin/bash daemon Service account bin Service account sys Service account sync /bin/sync games Service account man Service account lp Service account mail Service account news Service account uucp Service account proxy Service account
Как видите, хотя я и ожидал увидеть оболочку входа в систему любых пользователей, не являющихся служебными учетными записями, я пропустил учетную запись sync, которая... ну, это артефакт более ранней эпохи (до -1993), который использовался для безопасного завершения работы систем без необходимости знать пароль root. Я не знаю ни одной современной системы, которая все еще использует его. Если я ошибаюсь, пожалуйста, дайте мне знать в комментариях. Всегда рад узнать что-то новое!
Кроме того, обратите внимание, что если вы хотите в полной мере использовать sed, вы также должны быть знакомы с основными регулярными выражениями.
JQ:
Мы уже кратко встречались с jq уже в разделе Взаимодействие с командной консолью. Если вы работаете с JSON, скорее всего, вы уже знакомы с jq. Это утилита для анализа и форматирования документов JSON. Оператор . сам по себе представляет корень документа. Вы можете использовать оператор . для ссылки на дочерние элементы корневого документа. Дан документ JSON с именем pets.json, который выглядит так:
{
"pets": {
"cat": {
"name": "Mr Fuzzy",
"color": "calico",
"age": 8
},
"dog": {
"name": "Sir Barky",
"color": "blonde",
"age": 12
}
}
}
Затем эта команда, jq . pets.json, отобразит весь документ в красивом печатном формате, который будет выглядеть идентично необработанному документу выше. Эта команда, jq .pets pets.json, отобразит поле pets и дочерние поля cat и dog. Эта команда jq .pets.dog отобразит только поле собака, как показано ниже:
{
"name": "Sir Barky",
"color": "blonde",
"age": 12
}
Он также позволяет работать с массивами JSON (включая фрагменты массива), встроенными функциями для фильтрации, сопоставления значений, преобразования документов и, как вы уже догадались, можно использовать регулярные выражения для сопоставления с функцией test, чтобы определить, является ли ввод соответствует критериям выражений.
Опять же, вся тема слишком велика для этой статьи, и уже есть множество статей, посвященных использованию jq. Вот ссылка для начала.
И поскольку это может продолжаться вечно, я собираюсь покончить с тем, что порекомендую как самые простые, так и самые сложные инструменты. Легкий, потому что это не вызывает сомнений, что он вам понадобится, и сложный, потому что мнения настолько сильны, что иногда могут быть ядовитыми. Редакторы на основе терминала
Редакторы терминала:
Редакторы терминалов — очень самоуверенная тема. У каждого есть любимчик. Когда дело доходит до редакторов для терминала, почти все думают либо о vim, либо о emacs. Хотя эти 2 доминируют в пространстве редакторов терминала, для терминала доступно удивительное количество редакторов. Большинство из них я никогда не использовал, по крайней мере, очень давно, но помимо vim и emacs есть несколько достойных упоминания.
Nano — Nano является частью экосистемы GNU с 2001 года. Он был создан как бесплатная замена редактору Pico, который был частью Pine, который в то время был почтовым клиентом для UNIX-систем. Pico был встроенным в Pine редактором, который использовался для создания и редактирования электронных писем. Его самое большое преимущество, на мой взгляд, заключается в том, что его можно найти во многих системах, он маленький и простой. Как киндер ви.
Mcedit-Midnight Command — достаточно популярный файловый менеджер терминала (ну, раньше был, но я правда больше не знаю тбх). Mcedit — встроенный редактор. Единственная причина возиться с этим, если вы используете MC. Я определенно не думаю, что стоит устанавливать MC, чтобы иметь возможность использовать Mcedit, но если вы уже являетесь пользователем MC, я думаю, что люди иногда забывают об этом.
Существует много альтернатив, но я придаю большое значение повсеместности и передаче навыков. Если я хорошо потрачу время на изучение инструмента, я хочу убедиться, что этот инструмент доступен в как можно большем количестве сред, и что, если возможно, я могу перенести эти навыки на другие инструменты.
Вим и Эмакс:
Священные войны между vim и emacs хорошо задокументированы, как и сами редакторы, с бесчисленным количеством доступных руководств, поэтому я не буду их здесь описывать.
Единственный комментарий, который я должен добавить о них, заключается в том, что они оба соответствуют моим критериям повсеместности и передачи навыков. Их обоих можно найти практически на любой платформе по умолчанию, и навыки обоих имеют некоторый перенос на другие инструменты.
Что касается переноса навыков, все оболочки, которыми я пользовался за последние 20 лет, имеют сочетания клавиш как для emacs, так и для vi. Это означает, что я могу редактировать в интерактивной оболочке с помощью тех же нажатий клавиш, что и в своем редакторе. Я также могу использовать привязки клавиш emacs или vim в моих любимых графических редакторах, например,, во всех редакторах JetBrains, Eclipse, VS Code и т. д. Если бы только Word или Google Docs могли это сделать.
Что касается конкретно vi/vim/nvim, если вы можете использовать vim или neovim, вы можете использовать vi, несмотря на его возраст. Вы можете скучать по причудливым колокольчикам и свисткам, которые дают вам другие, но с вами все будет в порядке. Вот почему люди относятся к ним так, как если бы они были чем-то особенным. Я начинаю отделять неовим в голове от вима. С объявлением о том, что vim будет переписывать свой движок vimscript с нуля, вместо того, чтобы следовать по стопам neovim и использовать уже существующий язык для создания плагинов и пользовательских скриптов, я думаю, что это оправдано. Хотя мы всегда будем видеть обратную совместимость между nvim и vim, по крайней мере, в обозримом будущем, я думаю, что vim совершил ошибку и за это пострадает. Зачем изобретать велосипед и тратить все время, силы и слезы на создание с нуля совершенно нового движка, его отладку и т. д., вместо того, чтобы просто предоставить средства для уже существующего языка, который хорошо известен, хорошо документирован и уже полюбили?
Лично я использую неовим. Мой выбор исходит из двух простых фактов.
- Это легче
- Мой первый опыт работы с emacs был разочаровывающим, а сочетания клавиш причиняли боль моим рукам после продолжительного использования.
- Дополнительный факт: когда я впервые начал пробовать emacs, было множество разных версий, и совместимость между ними не гарантировалась. Возможно, это способствовало некоторым моим разочарованиям.
Как всегда, какие бы инструменты вы ни выбрали, чтобы посвятить свое время обучению, делайте это обдуманно и делайте это хорошо.