воскресенье, 6 апреля 2008 г.

10 привычек хорошего иcпользования UNIX

IBM LogoГде-то примерно такого названия статья попалась на сайте developerWorks IBM. Приссмотрелся, кажется UNIX tips: Learn 10 good UNIX usage habits интересна и, возможно, поможет не только новичку в *nix. Как говорил мой одноклассник (”снэмал не я”) перевод мой, не бэйте больна. ;)

Вступление

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

Усвойте 10 хороших привычек

Вод этот список:

  1. Делайте дерево каталогов в одну строку
  2. Изменяйте каталог - не переносите архив
  3. Обьеденяйте ваши комманды с управляемымы операторами
  4. Заключайте переменный в кавычки с осторожностью.
  5. Используйте управляющие последовательности (escape sequences) для управления длинным вводом
  6. Группируйте ваши комманды в список
  7. Используйте xargs вне find
  8. Знайте, когда “grep” следует делать подсчет и когда он должен шагнуть в сторону (не могу нормально перевести “it should step aside.”)
  9. Находите некоторые поля в выводе, не только строки (тоже как-то коряво)
  10. Перестаньте туннелировать cat (Stop piping cats). (просто жесть!)

Делайте дерево каталогов в одну строку

На листинге 1 показано одину с самых распространённых плохих привычек в UNIX: создание каталогов по-очереди.

Листинг 1. Пример №1: Создание дерева каталогов по-одному

~ $ mkdir tmp
~ $ cd tmp
~/tmp $ mkdir a
~/tmp $ cd a
~/tmp/a $ mkdir b
~/tmp/a $ cd b
~/tmp/a/b/ $ mkdir c
~/tmp/a/b/ $ cd c
~/tmp/a/b/c $

Именно по-этому быстрее всего использовать опцию -p команды mkdir и сделать все родительские каталоги вместе с их детьми одной коммандой. Но даже администраторы, которые знают об этой опции, всё ещё содают по-одной директории. Это стоит вашего времени, чтобы добросовестно выработать хорошую привычку:

Листинг 2. Пример №1: Создание дерева одной командой

~ $ mkdir -p tmp/a/b/c

Вы можете использовать даную опцию, чтобы создать весь комплекс каталогов, которые часто всего используется в скриптах, а не просто иерархию. Например:

Листинг 3. Пример №1: Создание комплекса каталогов одной командой

~ $ mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

В прошлом, единственным оправданием для определения директории по отдельности было, что реализация mkdir не поддерживает этот вариант, но это не верно в большинстве систем. IBM, AIX ®, mkdir, GNU mkdir и другие, которые поддерживают Единую Спецификацию UNIX (Single UNIX Specification) теперь имеют эту опцию.

Для нескольких систем, которые до сих пор не имеют этой поддержки, можно использывать скрипт mkdirhier (смотрите в Resources), который является обёрткой для mkdir с этой опцией:

Листинг 3. Пример №1: Создание комплекса каталогов одной командой

~ $ mkdirhier project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

Изменяйте каталог - не переносите архив

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

Листинг 4. Пример №2: Использование опции -С при расспаковке архива

~ $ tar xvf -C tmp/a/b/c newarc.tar.gz

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

Обьеденяйте ваши комманды с управляемымы операторами

Вы, наверное, уже знаете, что в большинстве команднsх оболочек (shell), можно объединить команды в одной командной строке, поставив точку с запятой (;) между ними. Точка с запятой - это упрапляющий оператор shell (shell control operator), и хотя она полезна для связывания вместе несколько дискретных команд в одну командную строку, она не работает для всего. Например, предположим что вы используете точку с запятой для обьединения двух комманд, в которых правильно выполнение второй команды польностью зависит от успешного выполнения первой. Если первая команда не выполнилась так, как вы ожидали, то вторая команда всё равно выполнится, что неправильно. Вместо этого, используйте больше подходящие управляющие команды (некоторые с них описаны в этой статье). С тех пор, когда ваш shell их поддерживает, они стоят того, чтобы стать привычкой в использовании.

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

Используйте управляющий оператор && для обьединения двух комманд, чтобы вторая выполнилась только тогда, когда первая вернула только нулевой статус завершения (zero exit status). Другими словами, первая успешно выполнилась - вторая запустилась. Если же первая команда дала сбой, то вторая не запустится вообще. Например:

Листинг 5. Пример №3. Обьединение команд управляющими операторами

~ $ cd tmp/a/b/c && tar xvf ~/archive.tar

В этом примере архив ~/archive.tar расспакуется в каталог tmp/a/b/c, если только каталог существует. Если же каталога не существует, то команда tar даже не запустится.

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

Похожый оператор || обьединяет две команды, и запуск второй будет тогда, первая командв вернула не нулевой код возврата. Другими словами, когда первая команда успешна, то вторая не выполнится. Если произойдёт сбой первой команды, то выполнится вторая.Этот оператор часто используется для проверки существования каталога и создани его, если его нет:

Листинг 6. Пример №3: Обьединение команд управляющими операторами

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c

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

Листинг 7. Пример №3: Пример, обьединяющий управляющие операторы

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c && tar xvf -C tmp/a/b/c ~/archive.tar

Заключайте переменный в кавычки с осторожностью.

Всегда будьте внимательны с shell expansion и именами переменных. Вцелом, вложить вызовы переменных в двойные кавычки хорошая идея, если только у вас есть веские причины не делать этого. Точно так же, если у Вас алфавитно-цифровым название переменной следует непосредственно за текстом, убедитесь , что заключили название переменной в фигурные скобки ({}), чтобы отличить её от ближайшего текста. Иначе, интерпритатор shell примет следуемый текст за имя переменной и, скорее всего, вернёт пустой результат. Листинг 8 содержит примеры разного квотирования переменных и их последствия.

Листинг 8. Пример №4: Квотирование и не квотирование переменных

~ $ ~ $ ls tmp/
a b
~ $ VAR=”tmp/*”
~ $ echo $VAR
tmp/a tmp/b
~ $ echo “$VAR”
tmp/*
~ $ echo $VARa


~ $ echo “$VARa”

~ $ echo “${VAR}a”
tmp/*a
~ $ echo ${VAR}a
tmp/a
~ $

Используйте управляющие последовательности (escape sequences) для управления длинным вводом

Вы уже, наверное, видели примеры кода, в котором backslash (\) продолжает длинную строку в следующей, и вы знаете, что большинство shell-оболочек рассматривают ваш ввод последовательных строк, присоединённых косой чертой, как одину длинную команду. Тем не менее, Вы не сможете воспользоваться этой функцией в командной строке, как часто, как вам хочется. Backslash особенно удобен, если ваш терминал не поддерживает multi-line wrapping должным образом или когда командная строка меньше чем обычно ( например, когда у вас длинный путь в приглашении). Backslash также полезен для лучшего понимания длинных строк, как показано на следующем примере:

Листинг 9. Пример №5: Использование / для длинного ввода

~ $ cd tmp/a/b/c || \
> mkdir -p tmp/a/b/c && \
> tar xvf -C tmp/a/b/c ~/archive.tar

Кроме того, следующие строки также работают:

Листинг 10. Пример №5: альтернативный пример использования / для длинного ввода

~ $ cd tmp/a/b/c \
> || \
> mkdir -p tmp/a/b/c \
> && \
> tar xvf -C tmp/a/b/c ~/archive.tar

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

Примечание: В большенстве коммандных оболочек, когда вы нажмёте клавишу “Вверх”, текущая многострочная строка превратится в одну длинную.

Группируйте ваши комманды в список

Большинство командных оболочек имеют возможность группировать набор комманд в списки, таким образом чтобы вы могли передать их общий вывод в поток ( a pipeline) или переправить любые с потоков в одно место. Вы можете вообще делать это, управляя списком команд в подоболочке (subshell) или управляя списком команд в текущей командной оболочке.

Запуск списка команд в подоболочке (subshell)

Используйне одиночные скобки для указания списка команд в одной граппе. Это запустит команды в новом subshell и позволит вам передавать или собрать вывод, как показано в следующем примере:

Листинг 11. Пример №6: Запуск списка комманд в подоболочке

~ $ ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && \
> VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \
> | mailx admin -S “Archive contents”

В этом примере, содержание архива расспаковывается в tmp/a/b/c/, а вывод из группы команд, в том числе перечень извлеченных файлов, отправляется по почте на адрес admin.

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

Запуск списка команд в текущей оболочке

Используйте фигурные скобки ({}) для указания списка команд группы для запуска в текущей оболочке. Убедитесь, что есть пробелы между скобками и командами или shell может неправильно их интерпритировать. Также, убедитесь, что последняя команда в гуппе заканчивается точкой с запятой, как в следующем примере:

Листинг 12. Пример №6: Запуск списка комманд в текущеё оболочке

~ $ { cp ${VAR}a . && chown -R guest.guest a && \
> tar cvf newarchive.tar a; } | mailx admin -S “New archive”

Используйте xargs вне find

Используйте инструмент xargs как фильтр, для эфективного использования результатов вывода команды find. Общим принцыпом этого является, что запуск find предоставит список файлов, удовлитворяущих некоторым критериям. Этот список передается в xargs, который затем запускает некоторые другие полезные команды с этим спиком файлов как аргумент, как в следующем примере:

Листинг 13. Пример класического использования xargs

~ $ find some-file-criteria some-file-path | \
> xargs some-great-command-that-needs-filename-arguments

Однако, не думайте, что xargs выступает помощиком find; это - один из тех недостаточно использованных инструментов, который, когда использование войдёт в привычку, вы захотите применять к всему, в том числе в следующих целях.

Получение списка, разделённого пробелами

В этом простом вызове, xargs выступает как фильтр, который получает ввод как список (каждый член с новой строки). Утилита вставляет членов списка в одну строку, разделённую пробелами:

Листинг 14. Пример вывода xargs

~ $ xargs
a
b
c
Control-D
a b c
~ $

Вы можете послать вывод любой утилыты, которая выводит имена файлов, через xargs для получения аргументов для утилиты, получающей имена файлов, как в следующем примере:

Листинг 15. Пример использования xargs

~/tmp $ ls -1 | xargs
December_Report.pdf README a archive.tar mkdirhier.sh
~/tmp $ ls -1 | xargs file
December_Report.pdf: PDF document, version 1.3
README: ASCII text
a: directory
archive.tar: POSIX tar archive
mkdirhier.sh: Bourne shell script text executable
~/tmp $

Команда xargs может большее, чем прохождение по именам файлов. Успользуйте её для получения текста в одну строку:

Листинг 16. Пример №7: Использование xargs для вывода текста в одну строку

~/tmp $ ls -l | xargs
-rw-r–r– 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r–r– 1 \
root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 \
16:07 a -rw-r–r– 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 \
joe joe 3239 Sep 30 12:40 mkdirhier.sh
~/tmp $

Будьте осторожны с xargs

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

Знайте, когда “grep” следует делать подсчет и когда он должен шагнуть в сторону

Избегайте отправки grep в канал (piping) wc -l, чтобы подсчитать количество строк вывода. Опция grep -c выводит количество строк, которые подпадают под шаблон, и основном быстрее чем канал на wc, как в следующем примере:

Листинг 17. Пример №8: Подсчёт строк с использование grep и без

~ $ time grep and tmp/a/longfile.txt | wc -l
2811

real 0m0.097s
user 0m0.006s
sys 0m0.032s
~ $ time grep -c and tmp/a/longfile.txt
2811

real 0m0.013s
user 0m0.006s
sys 0m0.005s
~ $

С добавлением фактора скорости, опция -c является лучшим способом сделать подсчёт. В ситуации с многими файлами, grep с параметром -c возвращает количество строк для каждого файла, по одному на строку, в это время как pipe с wc возвращает общее количество для всех файлов.

Однако, независимо от скорости работы, этот пример демонстрирует другую распространенную ошибоку, которую следует избегать. Эти методы подсчёта возвращают количество строк, которые содержат подходящий шаблон - и если это то, что вы ищете, то это прекрасно. Но, в случае, когда строки имеют множественные образцы вложений шаблона, этот метод не даст правильное количество найденых образцов. Для подсчёта количества использований, используйте wc в конце концов. Сначала, запустите команду grep с опцией -o, если ваша версия уё поддерживает. Этот параметр выводит только подходящий шаблон, один на строку, но не саму строку. Но вы не можете использовать её в вместе с параметром -c option, так что используйте wc -l для подсчёта строк, как показано в примере:

Листинг 18. Пример №8: Подсчёт подходящих шаблонов

~ $ grep -o and tmp/a/longfile.txt | wc -l
3402
~ $

В этом случае, вызов wc немножко быстрее, чем второй вызов grep с пустым шаблоном и подсчётом количества строк(как grep -c).

Находите некоторые поля в выводе, не только строки

Инструмент awk предпочтителен, чем grep, когда Вы хотите найти соответствия в только определенной области строк вывода и не только где-нибудь в строках.

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

Листинг 19. Пример №9: Использование grep для поиска в спецефических полях

~/tmp $ ls -l /tmp/a/b/c | grep Dec
-rw-r–r– 7 joe joe 12043 Jan 27 20:36 December_Report.pdf
-rw-r–r– 1 root root 238 Dec 03 08:19 README
-rw-r–r– 3 joe joe 5096 Dec 14 14:26 archive.tar
~/tmp $

В этом примере, grep вывод строки в которых, время изменения в Dec, а так же хорошо выводит и файлы с именем Dec. Ведь, файл, такой как December_Report.pdf, подходит, даже если его изменяля в январе. Это возможно не то, что вы хотели. Для нахождения по шаблону в особенном поле, лучше использовать awk, где относительный оператор соответствует точной области, как в примере:

Листинг 20. Пример №9: Использование awk для поиска в спецефических полях

~/tmp $ ls -l | awk ‘$6 == “Dec”‘
-rw-r–r– 3 joe joe 5096 Dec 14 14:26 archive.tar
-rw-r–r– 1 root root 238 Dec 03 08:19 README
~/tmp $

Смотрите Ресурсы для лучшего понимания awk.

Перестаньте туннелировать cat

Одна с основных-но-общих ошибочного использования grep связана с отправкой в канал вывода cat в grep для поиска строки в файле. Это абсолбтно излишне и пустая трата времени, потому как утилиты, такие как grep, получают имя файла как аргумент. Вам просто ненадо использовать cat в этом случае, как и в примере:

Листинг 21. Пример №10: Использование grep с использованием cat и без

~ $ time cat tmp/a/longfile.txt | grep and
2811

real 0m0.015s
user 0m0.003s
sys 0m0.013s
~ $ time grep and tmp/a/longfile.txt
2811

real 0m0.010s
user 0m0.006s
sys 0m0.004s

~ $

Эта ошибка относится к множеству средств. Поэтому большинство инструментов принимают стандартный ввод в качестве аргумента с использованием дефиса (-), даже аргумент за использование cat для множественной вставки файлов в stdin часто не действительный. В дествительности, это только необходимо для связки с каналом нескольких фильтрующих параметров cat.

Вывод: Перенимайте хорошие привычки

Очень хорошо получить привычки командной строки для чего-то плохого в использовании. Вредные привычки замедляют вас и часто приводят к неожиданным ошибкам. Эта статья представляет 10 новых привычек, которые могут помочь Вам отказаться от многих из наиболее распространенных ошибок. Принятие этих хороших привычек является позитивным шагом на пути к улутшении навыков владения командной строки UNIX.

скопировано с .wpal