Грамотное владение shell — один из самых важных навыков, которыми вы как программист должны обладать. Unix shell — одна из самых мощных идей, реализованных в коде, и она должна стать вашей второй натурой. Ни один другой инструмент и близко не сравним с возможностью быстрого выполнения сложных задач или с сохранением этих команд в виде скриптов.
В своей работе я использую Vim в качестве редактора, а Unix — в качестве «IDE». Я не модифицирую свой vimrc, чтобы добавить в него функции IDE; самый важный плагин, который использую ежедневно — это Ctrl+P, и он нужен мне только для упрощения открытия файлов. Грамотное владение Vim — ценный навык, но важно понимать, когда от него нужно отказаться. В своей повседневной работе я взаимодействую с несколькими терминалами: обычно в одном из них есть Vim, второй используется для запуска сборок или демонов, а в третьем запущен shell, способный выполнить любые мои команды.

Постоянно открытый shell позволяет мне выполнять сложные задачи и отвечать на сложные вопросы. Интересные вещи я нахожу при помощи git grep, масштабные операции поиска и замены я выполняю через sed, отвечаю на вопросы с помощью awk, а более тонкие задачи я выполняю создаваемыми по ходу работы командами и конвейерами shell. Я обладаю свободой творческого решения задач без ограничений, заложенных проектировщиками IDE.
Вот пример задачи, с которой я недавно столкнулся: у меня было множество изменений в репозитории git. Я хотел восстановить удалённые файлы, не теряя другие свои изменения, но их были сотни. Как оптимальнее всего будет решить эту проблему?
Я начал с оценки масштаба проблемы при помощи команды
С этим уже можно работать. Я добавил
Очень хорошо — мы создали список файлов, с которыми нужно работать. Стоит заметить, что можно было бы не использовать
Однако сейчас мы просто пишем «одноразовую» команду для решения конкретной временной проблемы, поэтому её совершенство для нас не так важно. Никто не будет проверять эту команду. В таких ситуациях я часто решаю по одной проблеме за раз: «отфильтровываем список» и «преобразуем список». Как бы то ни было, последним шагом будет использование этого списка файлов для решения проблемы при помощи команды xargs.
Давайте рассмотрим ещё несколько примеров интересных одноразовых конвейеров shell.
Естественно, для поиска этих примеров я написал конвейер shell:
Что здесь происходит:
Эта команда, написанная за считанные секунды, находит, характеризует, фильтрует и сортирует мою историю shell по сложности команд. Вот пара крутых команд shell, которые мне удалось найти:
Воспроизведение 50 самых новых видео в папке при помощи mpv:
Я постоянно использую эту команду. Если я хочу посмотреть видео позже, то использую для этого файла touch, чтобы он отображался в начале этого списка. Ещё одна команда передаёт при помощи
А вот, что происходит на стороне моего друга:
Кстати, tar — это недооценённый инструмент для перемещения групп файлов по конвейеру. Он может считывать и записывать tarball в stdin и stdout!
Надеюсь, эта статья дала вам представление о мощи Unix shell. Если вы хотите больше узнать о командной оболочке, то рекомендую shellhaters.org в качестве введения в различные части спецификации POSIX, связанные с shell. Не бойтесь спецификации — это краткий, исчерпывающий и понятный текст, в котором полно примеров. Ещё я крайне рекомендую уделить время изучению конкретно awk: вот краткий туториал.
Серверы для разработчиков и не только! Аренда виртуального сервера на базе новейших процессоров AMD и Intel, хранилище на основе NVMe дисков для размещения проектов любой сложности, создавайте собственную конфигурацию сервера в пару кликов!
Подписывайтесь на наш чат в Telegram.

В своей работе я использую Vim в качестве редактора, а Unix — в качестве «IDE». Я не модифицирую свой vimrc, чтобы добавить в него функции IDE; самый важный плагин, который использую ежедневно — это Ctrl+P, и он нужен мне только для упрощения открытия файлов. Грамотное владение Vim — ценный навык, но важно понимать, когда от него нужно отказаться. В своей повседневной работе я взаимодействую с несколькими терминалами: обычно в одном из них есть Vim, второй используется для запуска сборок или демонов, а в третьем запущен shell, способный выполнить любые мои команды.

Постоянно открытый shell позволяет мне выполнять сложные задачи и отвечать на сложные вопросы. Интересные вещи я нахожу при помощи git grep, масштабные операции поиска и замены я выполняю через sed, отвечаю на вопросы с помощью awk, а более тонкие задачи я выполняю создаваемыми по ходу работы командами и конвейерами shell. Я обладаю свободой творческого решения задач без ограничений, заложенных проектировщиками IDE.
Вот пример задачи, с которой я недавно столкнулся: у меня было множество изменений в репозитории git. Я хотел восстановить удалённые файлы, не теряя другие свои изменения, но их были сотни. Как оптимальнее всего будет решить эту проблему?
Я начал с оценки масштаба проблемы при помощи команды
git status
, которая показала мне сотни удалённых файлов, которые необходимо было восстановить. Понятно, что такие объёмы работы вручную выполнять непрактично, поэтому я ввёл git status -s
, чтобы получить более удобные для конвейера результаты.$ git status -s
D main/a52dec/APKBUILD
D main/a52dec/a52dec-0.7.4-build.patch
D main/a52dec/automake.patch
D main/a52dec/fix-globals-test-x86-pie.patch
D main/aaudit/APKBUILD
D main/aaudit/aaudit
D main/aaudit/aaudit-common.lua
D main/aaudit/aaudit-repo
D main/aaudit/aaudit-server.json
D main/aaudit/aaudit-server.lua
...
С этим уже можно работать. Я добавил
grep '^ D'
, чтобы отфильтровать все строки, которые не были удалены, и пропустил остальные через awk '{ print $2 }'
, чтобы извлечь только имена файлов. Часто я запускаю незавершённый конвейер, чтобы проверить свою работу:$ git status -s | grep '^ D' | awk '{ print $2 }'
main/a52dec/APKBUILD
main/a52dec/a52dec-0.7.4-build.patch
main/a52dec/automake.patch
main/a52dec/fix-globals-test-x86-pie.patch
main/aaudit/APKBUILD
main/aaudit/aaudit
main/aaudit/aaudit-common.lua
main/aaudit/aaudit-repo
main/aaudit/aaudit-server.json
main/aaudit/aaudit-server.lua
...
Очень хорошо — мы создали список файлов, с которыми нужно работать. Стоит заметить, что можно было бы не использовать
grep
и получить тот же результат при помощи одного awk
:$ git status -s | awk '/^ D/ { print $2 }'
main/a52dec/APKBUILD
main/a52dec/a52dec-0.7.4-build.patch
main/a52dec/automake.patch
main/a52dec/fix-globals-test-x86-pie.patch
main/aaudit/APKBUILD
main/aaudit/aaudit
main/aaudit/aaudit-common.lua
main/aaudit/aaudit-repo
main/aaudit/aaudit-server.json
main/aaudit/aaudit-server.lua
...
Однако сейчас мы просто пишем «одноразовую» команду для решения конкретной временной проблемы, поэтому её совершенство для нас не так важно. Никто не будет проверять эту команду. В таких ситуациях я часто решаю по одной проблеме за раз: «отфильтровываем список» и «преобразуем список». Как бы то ни было, последним шагом будет использование этого списка файлов для решения проблемы при помощи команды xargs.
$ git status -s | awk '/^ D/ { print $2 }' | xargs git checkout --
Давайте рассмотрим ещё несколько примеров интересных одноразовых конвейеров shell.
Естественно, для поиска этих примеров я написал конвейер shell:
$ history | cut -d' ' -f2- | awk -F'|' '{ print NF-1 " " $0 }' | sort -n | tail
Что здесь происходит:
history
выводит список истории моих команд shell.cut -d' ' -f2-
удаляет первое поле из каждой строки, используя в качестве разделителя пробел.history
нумерует каждую команду, а эта часть удаляет номер.awk -F'|' '{ print NF-1 " " $0 }
приказывает awk использовать в качестве разделителя полей каждой строки символ | и вывести в качестве префикса каждой строки количество полей. Эта команда выводит каждую строку из моей истории с префиксом — количеством вхождений оператора конвейера в этой строке.sort -n
сортирует этот список численно.tail
выводит последние 10 элементов.
Эта команда, написанная за считанные секунды, находит, характеризует, фильтрует и сортирует мою историю shell по сложности команд. Вот пара крутых команд shell, которые мне удалось найти:
Воспроизведение 50 самых новых видео в папке при помощи mpv:
ls -tc | head -n50 | tr '\n' '\0' | xargs -0 mpv
Я постоянно использую эту команду. Если я хочу посмотреть видео позже, то использую для этого файла touch, чтобы он отображался в начале этого списка. Ещё одна команда передаёт при помощи
netcat
tarball пропатченной версии Celeste моему другу, за исключением (больших) ресурсов игры. Процесс передачи отображается при помощи pv:find . ! -path './Content/*' | xargs tar -cv | pv | zstd | nc 204:fbf5:... 12345
А вот, что происходит на стороне моего друга:
nc -vll :: 12345 | zstdcat | pv | tar -xv
Кстати, tar — это недооценённый инструмент для перемещения групп файлов по конвейеру. Он может считывать и записывать tarball в stdin и stdout!
Надеюсь, эта статья дала вам представление о мощи Unix shell. Если вы хотите больше узнать о командной оболочке, то рекомендую shellhaters.org в качестве введения в различные части спецификации POSIX, связанные с shell. Не бойтесь спецификации — это краткий, исчерпывающий и понятный текст, в котором полно примеров. Ещё я крайне рекомендую уделить время изучению конкретно awk: вот краткий туториал.
На правах рекламы
Серверы для разработчиков и не только! Аренда виртуального сервера на базе новейших процессоров AMD и Intel, хранилище на основе NVMe дисков для размещения проектов любой сложности, создавайте собственную конфигурацию сервера в пару кликов!
Подписывайтесь на наш чат в Telegram.
