GNU parallel і xargs. Паралельний запуск кількох копій команди із різними аргументами. Будьте обережні за допомогою xargs. А тепер пошук за цілісними словами

xargs- утиліта для формування списку аргументів та виконання команди. Тобто xargs дає змогу викликати будь-яку команду з аргументами. У команди xargs є два компоненти. По-перше, ви повинні вказати файли, які вас цікавлять. По-друге, ви повинні встановити команду або скрипт, який ви хочете застосувати до кожного з цих файлів.

xargs - розбиває вхідний потік на аргументи та передає їх виконання будь-якій команді (за умовчанням echo). Читає або зі стандартного введення або через pipe.

Режими обробки xargs вхідних даних

    За замовчуванням роздільником аргументів вважається будь-який символ пробілу: пробіл, табуляція, вертикальна табуляція або переклад рядка. Але як і в командній оболонціможна використовувати "" або \ щоб запобігти розбиття аргументу.

    Режим, що включає параметр -L. Практично ідентичний попередньому, за винятком того, що xargs запам'ятовує, який аргумент на якому рядку знаходиться. Більше того, якщо рядок закінчується пробілом або табуляцією, наступний рядоквважається продовженням поточної.

    По рядках. Включається під час використання опції -I або -0. При цьому весь рядок вважається одним цілим аргументом, незважаючи на прогалини та табуляції всередині. Для -I кінцем рядка є символ \n а для -0 символ \0

    Приклад: пошук у /home/user1 всіх файлів, імена яких закінчуються на ".txt", та копіювання в іншу директорію. find /home/user1 -name "*.txt" | xargs cp -av --target-directory=/home/backup/ --parents

    Знайти у всіх файлах, розташованих у каталозі /etc/samba входження словосполучення logon home. $ find /etc/samba | xargs grep -ni "logon home"

    Видалити список файлів. Шляхи до файлу записані у файл delfiles.txt xargs rm< delfiles.txt

Про утиліту xargs написано дуже багато – що можна написати ще? Але якщо, що називається, копнути глибше, то з'ясовується, що в багатьох публікаціях викладаються лише самі основи, але немає головного: не пояснюється, як можна застосовувати xargs у реальній практиці. Статей з розбором складних і нетривіальних варіантів застосування цього дуже корисного для системного адміністратораінструменту, на жаль, обмаль. Саме тому ми написали свою статтю і постаралися включити до неї якнайбільше прикладів використання xargsдля вирішення різноманітних проблем.

Спочатку ми розглянемо принцип роботи xargs і розберемо простіші приклади, а потім перейдемо до розбору складних і цікавих кейсів.

Згадуємо основи

Принцип роботи xargs можна описати так: програма бере дані зі стандартного введення або з файлу, розбиває їх відповідно до вказаними параметрами, а потім передає іншій програмі як аргумент.

У загальному виглядісинтаксис команди xargs можна так:

[команда_генератор_списка] | xargs [опції_xargs] [команда]

Розглянемо, як це працює, на матеріалі простих і хрестоматійних прикладів.

Видалення файлів

Одна з найчастіших ситуацій, в яких використовується xargs, - видалення файлів, знайдених за допомогою команди find.

Уявімо собі наступну ситуацію: є директорія, в якій зберігається велика кількістьфайлів. З неї потрібно видалити файли певного типу(У нашому прикладі - файли з розширенням *.sh). Щоб здійснити цю операцію, потрібно передати xargs виведення команди find, і до файлів із зазначеним розширенням буде застосовано команду -rm:

$ ls one.sh one.py two.sh two.py $ find . -name "*.sh" | xargs rm -rf $ls one.py two.py

Зазначимо, що операцію видалення файлів можна здійснити і без xargs, а за допомогою команди

$find. -name "*.sh" -exec rm -rf "()" \

Описаний спосіб не спрацює, якщо в імені одного з файлів, що видаляються, міститься пробіл. Ім'я, що складається з двох слів, розділених пробілом, не буде сприйнято як єдине ціле.

Проілюструємо це наступним прикладом:

$ ls new file.sh one.sh one.py two.sh two.py $ find . -name "*.sh" | xargs rm -rf $ls New file.sh one.py two.py

Як бачимо, файл, в імені якого є пробіл, не було видалено.

Для вирішення цієї проблеми використовується опція print0 для команди find і опція -0 для команди xargs. Вона замінює стандартний роздільник (перенесення рядка на нуль-символ (\x0), який і означає кінець рядка, що зберігається:

$find. -name "*.sh" -print0 | xargs -0 rm -rf

Xargs може також допомогти, наприклад, швидко видалити все тимчасові файли, що мають розширення tmp:

$ find /tmp-name "*.tmp"| xargs rm

Стиснення файлів

Стиснути всі файли в поточній директорії за допомогою gzip можна, ввівши таку команду:

$ls | xargs -p -l gzip

Розглянемо ще один приклад: стиск за допомогою tar всіх файлів з розширенням *.pl:

$find. -name "*.pl" | xargs tar-zcf pl.tar.gz

Перейменування файлів

За допомогою xargs можна здійснювати масове перейменуванняфайлів. Уявімо, що ми маємо групу файлів з розширенням *.txt, і нам потрібно замінити це розширення на *.sql. Це можна зробити за допомогою xargs та потокового текстового редактора sed:

$ls | sed -e "p;s/.txt$/.sql/" | xargs -n2 fmv

У результаті виконання на консоль буде виведено список перейменованих файлів.

За допомогою xargs можна також додавати до додаткові елементидо імен файлів (наприклад, дату):

$ls | xargs -I FILE mv ()<...>-{}

Замість<..>можна підставити все, що завгодно.
Фігурні дужки () у цьому прикладі означають "поточний аргумент" (тобто поточне ім'я файлу).

Зміна прав для папок та файлів

За допомогою xargs можна також прискорити процес зміни прав на файли та папки для певного користувачачи групи. Припустимо, нам потрібно знайти всі папки користувача rootта замінити їх власника на temp. Ця операція здійснюється за допомогою команди:

$find. -group root -print | xargs chown temp

Щоб знайти всі папки групи root та замінити групу на temp, використовується команда:

$find. -group root -print | xargs chgrp temp

Xargs та find: складні операції

За допомогою команд find і xargs можна виконувати більш складні операції. Ось так, наприклад, можна видалити тимчасові файли, створені понад 7 днів тому:

$ find /tmp -type f-name "*" -mtime +7 -print0 | xargs -0 rm -f

А ось так – примусово зупинити процеси, які вже працюють понад 7 днів:

$ find /proc -user myuser -maxdepth 1 -type d -mtime +7 -exec basename() \; | xargs kill -9

Xargs і сut

Xargs досить часто використовується в поєднанні з командою cut, що дозволяє вирізати рядки з текстових файлів. Розглянемо деякі практичні приклади. За допомогою наведеної нижче команди на консоль буде виведено список усіх користувачів системи:

$ cut -d: -f1< /etc/passwd | sort | xargs echo

А команда виду

File * | grep ASCII | cut-d":"-f1 | xargs -p vim

буде послідовно відкривати файли для редагування vim.
Звернімо увагу на опцію -p. Завдяки їй команда виконуватиметься у інтерактивному режимі: перед відкриттям кожного файлу запитуватиметься підтвердження (y/n).

На закінчення наведемо ще один складний і цікавий приклад- рекурсивний пошук файлів самого великого розміруу деякій директорії:

$find. -type f -printf "%20s %p\n" | sort-n | cut-b22- | tr "\n" "\000" | xargs -0 ls -laSr

Паралельний запуск процесів

Xargs часто використовується для паралельного запуску кількох процесів. Ось так, наприклад, можна одночасно стиснути кілька директорій у tar.gz:

$ echo dir1 dir2 dir3 | xargs -P 3 -I NAME tar czf NAME.tar.gz NAME

У цьому прикладі використовується ключ -P. Він вказує максимальна кількістьпроцесів, які виконуватимуться одночасно. Припустимо, що у нас на вході є 10 аргументів. Якщо ми введемо команду xargs з ключем -P 3, то буде запущено 3 екземпляри команди, наступної після xargs, з кожним із цих аргументів.

За допомогою xargs можна паралельно завантажувати з Інтернету безліч файлів:

У наведеному прикладі з вказаної адресибудуть завантажені всі графічні файлиз розширенням jpg; ключ -P вказує, що потрібно завантажувати по 10 файлів одночасно.

Попередні підсумки

Підіб'ємо попередні підсумки і сформулюємо кілька правил роботи з xargs.

  1. Xargs не працює з файлами, в імені яких є пробіл. Для вирішення цієї проблеми із командою xargs використовується опція −0. Пробіл в імені файлу можна обійти так: $ xargs -I FILE my_command “FILE”
  2. Команда xargs приймає команди зі стандартного введення, розділені пробілом або перекладом рядка. Щоб групувати ці команди, можна використовувати подвійні або одинарні лапки. Можна також вказати роздільник за допомогою опції -d;
  3. Якщо команді xargs не передати взагалі жодних аргументів, то за умовчанням буде виконано команду /bin/echo;
  4. У багатьох випадках команду xargs можна замінити циклом for. Наприклад, команда $find. -type f-and-iname "*.deb" | xargs -n 1 dpkg -I

    повністю еквівалента циклу

    $ for file in `find. -type f -and -iname "*.deb"`; do dpkg -I "$file"; done

Нетривіальні приклади

Основи ми згадали, типові варіантивикористання розглянули… Перейдемо тепер до складніших і нетривіальніших прикладів. До деяких з них ми додумалися самостійно, працюючи над повсякденними завданнями, а деякі почерпнули з сайту http://www.commandlinefu.com (усім бажаючим навчитися тонкощам роботи з командним рядкомдуже рекомендуємо час від часу його відвідувати - там часом можна знайти дуже корисні поради).

Банім IP-адреси зі списку

Щоб забанити IP-адреси зі списку, їх додати до IP tables з правилом DROP. Ця операція здійснюється за допомогою команди:

$cat bad_ip_list | xargs -I IP iptables -A INPUT -s IP -j DROP

Можна зробити і більше складну операціюі забанити всі адреси AS:

$ /usr/bin/whois -H -h whois.ripe.net -T route -i origin AS<номер>|egrep "^route"|awk "(print $2)" |xargs -I NET iptables -A INPUT -s NET -j DROP

Змінюємо формат URL

Перетворити URL типу «http%3A%2F%2Fwww.google.com» на «http://www,google.com» можна за допомогою команди:

Echo "http%3A%2F%2Fwww.google.com" | sed -e"s/%\(\)/\\\x\1/g" | xargs echo-e

Генеруємо пароль із 10 символів

Згенерувати надійний парольможна за допомогою команди виду:

$ tr -dc A-Za-z0-9_< /dev/urandom | head -c 10 | xargs

Генерувати паролі можна і без допомоги xargs: для цього існує спеціалізована утиліта pwgen. Деякі інші способи генерації паролів також описані .

Шукаємо бінарні файли, встановлені без використання dpkg

Така операція може бути потрібна у випадку, якщо, наприклад, машина стала жертвою хакерської атакиі на ній було встановлено шкідливе програмне забезпечення. Виявити, що за програми поставили зловмисники допоможе наступна команда (вона шукає запущені «бінарники», встановлені без використання менеджера пакетів dpkg):

$ сat /var/lib/dpkg/info/*.list > /tmp/listin ; ls /proc/*/exe |xargs -l readlink | grep -xvFf /tmp/listin; rm /tmp/listin

Видаляємо застарілі пакети ядра

$ dpkg -l linux-* | awk "/^ii/( print $2)" | grep -v -e `uname-r | cut-f1,2-d"-"`| grep-e | xargs sudo apt-get -y purge

Проблема видалення старих ядер вже обговорювалася на Хабре - див. (за цим посиланням можна знайти цікаві приклади команд).

Перетворимо скрипт на рядок

Іноді виникає потреба перетворити великий скрипт в один рядок. Зробити це можна так:

$ (sed "s/#.*//g"|sed "/^ *$/d"|tr "\n" ";"|xargs echo)< script.sh

Висновок

Як видно з зробленого огляду, можливості xargs набагато ширші, ніж це може здатися на перший погляд. Сподіваємося, що наведені у статті приклади виявляться вам корисними. Якщо вам відомі інші цікаві варіанти використання xargs - ласкаво просимо в коментарі.

Довгими зимовими вечорами я сидів і думав "ось прийде світлий час, я сяду і добре розберуся з цією загадковою утиліткою xarg". Ну от час схожий і настав - я сів розбиратися. Перше, що мені впало у вічі, це те, що man до неї досить загадковий, і з першого разу не просвітлює. на вікіпедії розуміння теж не додала, а скоріше навіть заплутала, тому я вирішив провести своє власне розслідування і написати з цього приводу невеликий мануалчик. Як відомо, поки пояснюєш і сам зрозумієш:)

Отже, xargs.

xargs це така утиліта командного рядка, що дозволяє викликати будь-яку команду з аргументами, взятими з стандартного входу. Причому аргументи можна передати відразу, а можна групувати по кілька штук. Вивчати ми будемо xargs версії 4.4.0, причому за рекомендацією man-а будемо використовувати лише нові аргументи, не помічені як deprecated (краще відразу звикати працювати правильно).

Отже, перше, що варто зрозуміти, це те, як xargs обробляє вхідний потік і ділить його на аргументи. Є кілька режимів, які залежать від опцій:

1. Звичайний. За замовчуванням роздільником аргументів вважається будь-який символ пробілу: пробіл, табуляція, вертикальна табуляція або переклад рядка. Але як і в командній оболонці можна використовувати "" або \ щоб запобігти розбиття аргументу.

2. Звичайний, з угрупованням. Режим, що включає параметр -L. Практично ідентичний попередньому, за винятком того, що xargs запам'ятовує, який аргумент на якому рядку знаходиться. Більше того, якщо рядок закінчується пробілом або табуляцією, наступний рядок вважається продовженням поточного.

3. По рядках. Включається під час використання опції -I або -0. При цьому весь рядок вважається одним цілим аргументом, незважаючи на прогалини та табуляції всередині. Для -I кінцем рядка є символ \n а для -0 символ \0

Проведемо пару випробувань, щоб краще зрозуміти все це. Створимо файл test з наступним вмістом (== у файл заносити не треба):
==
arg1
arg2 space
"arg3 quoted"
arg4\ escaped
arg5 with
continue
==
(Після "arg5 with" має бути пробіл)
А також напишемо невеликий скрипт tp, який виводитиме свої аргументи поділяючи їх символом ":" і кількість:
==
#!/bin/bash
echo -n "@$#"
while [[ $1 != "" ]]; do echo -n ": $1"; shift; done
echo
==

Звичайний режим (виділення аргументів по пробіловим символам):
x $ cat test | xargs ./tp
@8:arg1:arg2:space:arg3 quoted:arg4 escaped:arg5:with:continue
Файл був розбитий на аргументи по пробельним символам, але рядки взяті в лапки і екрановані символом залишилися цілими.

Звичайний режим з угрупованням рядків не відрізняється від попереднього на цьому етапі.

Розбиття по рядках. Створимо другий тестовий файл наступною командою:
x $ cp testz && printf "\0arg6" >> testz
Перевіримо
x $ cat testz | xargs -0./tp
@2:arg1
arg2 space
"arg3 quoted"
arg4\ escaped
arg5 with
continue
:arg6

Як можна бачити аргумент всього 2. Перший довгий, що зберіг переклади рядків, лапки і \, а другий arg6. У файлі вони розділені символом нуля.

Щодо розділення параметрів можна ще сказати про опцію -d, яка вказує новий роздільник. Наприклад, спробуємо використовувати "3" як роздільник.
x $ cat test | xargs -d 3 ./tp
@2:arg1
arg2 space
"arg: quoted"
arg4\ escaped
arg5 with
continue
Відбувся розділення файлу на 2 частини на місці символу "3". Що примітно, таким чином можна емулювати опцію -0
x $ cat testz | xargs -d "x00" ./tp
@2:arg1
arg2 space
"arg3 quoted"
arg4\ escaped
arg5 with
continue
:arg6

З поділом вхідного потоку на аргументи здається розібралися, переходимо до підстановки параметрів.

Отже, xarg після своїх опцій чекає на команду, яку і виконуватиме. Усі вхідні аргументи розбиваються на групи, після чого задана командавикликається кожної групи, й у неї передаються всі аргументи з цієї групи.

Тепер розглянемо, як формуються групи.

1. Якщо опцій немає, то група одна, до неї потрапляють усі аргументи із потоку введення. Група нескінченного розміру, так би мовити:)

2. Опція -L n задає групування рядків. У команду передаються аргументи, що знаходяться на n рядках. Продемонструю на прикладах.
Угруповання по 1 рядку:
x $ cat test | xargs -L 1 ./tp
@1:arg1
@2:arg2:space
@1:arg3 quoted
@1:arg4 escaped
@3:arg5:with:continue
Видно, що другий рядок містить 2 аргументи, тому що вони обидва на одному рядку. А останній взагалі 3, тому що передостанній рядок "подовжується" за рахунок пробілу в кінці.

Тепер угруповання по 2 рядки. У команду потрапляють рядки 1 та 2; 3 та 4; і сирітка 5-та:
x $ cat test | xargs -L 2 ./tp
@3:arg1:arg2:space
@2:arg3 quoted:arg4 escaped
@3:arg5:with:continue

3. Угруповання за аргументами, що задається опцією -n x. Тут все прозоро: аргументи групуються по x штук і передаються до команди.
За одним аргументом:
x $ cat test | xargs -n 1 ./tp
@1:arg1
@1:arg2
@1:space
@1:arg3 quoted
@1:arg4 escaped
@1:arg5
@1:with
@1:continue
За 2 аргументи:
x $ cat test | xargs -n 2 ./tp
@2:arg1:arg2
@2:space:arg3 quoted
@2:arg4 escaped:arg5
@2:with:continue

3. Режим із підстановкою - опція -I. Для початку треба нагадати, що в даному режиміаргументи з потоку введення розбираються особливо. Кожен рядок це один цілий аргумент, склеювання рядків не провадиться. По-друге, опція -I має параметр - рядок, який замінюється в команді на аргумент:
x $ echo -e "A B\nC D" | xargs -I _ ./tp =_+_=
@ 1: = A B + A B =
@ 1: = C D + C D =
Легко помітити, що символ _ заданий як рядок підстановки аргументу, який використовується у команді двічі. Також видно, що аргументи виділяються цілими рядками, і пропуск не впливає на розбір. Команда викликається кожному аргументу.

З підстановкою все. Розглянемо важливі опції, що залишилися.
-r - не виконувати команду, якщо немає аргументів:
x $ cat /dev/null | xargs ./tp
@0
x $ cat /dev/null | xargs -r./tp
x $
Як бачимо, у другому випадку команда не здійснилася.

P - xargs буде вимагати підтвердження виконання кожної команди.

У цьому невеликий мануал завершено. Він виявився не зовсім коротким, зате сподіваюся зрозумілим;)

Відмовтеся від невдалих прийомів роботи в UNIX

Часто використовуючи якусь систему, ми звикаємо до деяких шаблонів роботи. Не завжди ці шаблони виявляються оптимальними. Іноді ми навіть набуваємо поганих звичок, які призводять до безладдя та незграбності в роботі. Один з найкращих шляхіввиправлення таких недоліків - вироблення звички використовувати хороші прийоми, які перешкоджають безладу. Ця стаття пропонує 10 методів роботи з командною рядком UNIX, гідних стати звичками, які допоможуть вам уникнути багато загальних недоліків та підвищити ефективність роботи. Докладний опискожного методу наведено після списку.

Засвоїмо 10 хороших звичок

Десять добрих методів, до яких варто звикнути:

Створюйте дерева каталогів однією командою

Лістинг 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, сьогодні мають цю опцію.

Для небагатьох систем, у яких відсутня ця можливість, слід використовувати скрипт mkdirhier (див. ), який є оболонкою для mkdir і виконує ту ж функцію.

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

Змінюйте шляхи; не переносіть архів

Ще один невдалий метод роботи - це переміщення архівного файла.tar до певного каталогу, якщо вам захотілося витягти архів саме до цього каталогу. Вам не варто таке робити. Ви можете розпакувати будь-який архівний файл.tar у будь-який каталог - для цього призначена опція -C. Використовуйте -C , щоб вказати каталог для розпакування:

Лістинг 4: Приклад хорошого методу роботи #2: Використання опції -C для розпакування архівного файлу.tar
~ $ tar xvf -C tmp/a/b/c newarc.tar.gz

Використання опції -C краще, ніж переміщення архівного файлу в потрібний вам каталог, зміна каталогу та вилучення вмісту файлу - особливо, якщо сам архівний файл знаходиться десь в іншому місці.

Поєднуйте ваші команди з операторами управління

Ви, ймовірно, вже знаєте, що в більшості оболонок ви можете комбінувати команди в одному командному рядку за допомогою точки з комою (;) між ними. Крапка з комою - це керуючий оператор оболонки, і хоча він призначений, щоб зв'язувати численні окремі команди в єдиний командний рядок, його застосування не завжди можливе. Наприклад, припустимо, що ви використовуєте крапку з комою для об'єднання двох команд, в яких виконання другої команди повністю залежить від успішного закінчення першої. Якщо перша команда не виконується так, як ви очікуєте, друга команда все ж таки запускається - і зазнає невдачі. Натомість, використовуйте більше відповідний операторуправління (деякі описані у цій статті). Якщо ваша оболонка підтримує їх, до них варто звикнути.

Запуск команди лише в тому випадку, якщо інша команда повернула нульове значення

Використовуйте оператор керування && для об'єднання двох команд таким чином, що друга команда буде виконуватися тільки якщо перша повернула нульове значення. Іншими словами, якщо перша команда виконується успішно, друга команда також запускається. Якщо перша команда не виконується, друга команда не запускається зовсім. Наприклад:

Лістинг 5. Приклад хорошого методу роботи #3: Поєднуйте команди з операторами управління
~ $ cd tmp/a/b/c && tar xvf ~/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 &&

Будьте уважні при використанні лапок у роботі зі змінними

Завжди будьте обережні з розширенням оболонки та іменами змінних. Взагалі, це хороша ідея- брати звернення до змінних у подвійні лапки, тільки якщо немає особливих причин не робити цього. Аналогічно, якщо безпосередньо за ім'ям змінної слід буквено-цифровий текст, ім'я змінної слід укласти в фігурні дужки(()), щоб відрізняти її від навколишнього тексту. Інакше оболонка інтерпретує замикаючий текст як частину імені змінної - і найімовірніший результат - нульовий кодповернення. У Лістингу 8 наведено приклади варіантів використання лапок з іменами змінних та отримані результати.

Лістинг 8. Приклад хорошого методу роботи #4: Використання (і не використання) лапок у роботі зі змінними
~ $ ls tmp/ab ~ $ 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 ~ $

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

Ви, ймовірно, зустрічали приклади коду, в якому зворотний слеш (\) продовжує довгий рядок, і ви знаєте, що більшість оболонок трактує те, що ви друкуєте в наступних рядках, приєднаних за допомогою зворотного слеша, як один довгий рядок. Тим не менш, ви можете отримати більше користівід цієї функції у командному рядку, використовуючи її частіше. Зворотний слеш особливо зручний, якщо ваш термінал не справляється належним чином з обробкою багаторядкових переносів або коли командний рядок коротший, ніж звичайно (наприклад, коли у вас в командному рядку вказано довгий шлях). Зворотний слеш також корисний виділення смислових частин довгого рядка, як у наступному прикладі:

Лістинг 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

Коли ви поділяєте рядок на безліч рядків, оболонка завжди розглядає її як одну цілу, видаляючи з отриманого довгого рядка всі зворотні слеші та зайві прогалини.

Примітка:У більшості оболонок, коли ви натискаєте стрілку вгору, весь мульти-рядок зображується у вигляді єдиного довгого рядка.

Об'єднуйте команди до списку

Більшість оболонок дозволяє об'єднувати набори команд до списку; таким чином, ви можете організувати конвеєрну передачу результатів роботи від однієї команди до іншої або перенаправити їх іншим способом. Ви можете, як правило, зробити це за допомогою запуску списку команд у додатковій або поточній оболонці.

Запуск списку команд у додатковій оболонці

Використовуйте круглі дужки для укладання списку команд в одну групу. Це дозволяє запустити команди в додатковій оболонці і перенаправити або в інший спосіб зібрати результати їх роботи, як показано в наступному прикладі:

Лістинг 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 .

Використання додаткових оболонок зручне у випадках, коли ви перевизначуєте змінні середовищау списку команд і не хочете приймати ці зміни у своїй поточній оболонці.

Запуск списку команд у поточній оболонці

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

Лістинг 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 | \ > xargs

Тим не менш, не думайте, що xargs - це лише доповнення до find; це один із тих інструментів, звикнувши до якого, хочеш працювати з ним постійно, наприклад, у таких випадках:

Передача списку з пробілами, що розділяють

У цій простій ілюстрації xargs схожий на фільтр, який бере на вхід список (кожен елемент на окремому рядку) і ставить його елементи на один рядок, розділяючи їх пробілами:

Лістинг 14. Приклад результату роботи команди xargs
~ $ xargsabc 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.

Команда 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 може спричинити скруту. За промовчанням символ кінця файлу - це нижнє підкреслення (_); якщо цей символ було передано на вхід як єдиний аргумент, все після нього буде ігноруватися. Як запобіжний засіб використовуйте прапорець -e , який без аргументів відключає символ кінця файлу.

Знайте, коли використовувати grep для підрахунку - а коли від нього краще відмовитись

Уникайте використовувати після grep команду wc -l для підрахунку кількості отриманих рядків. Опція -c у grep дозволяє підрахувати кількість рядків, які відповідають заданим шаблонам і загалом працює швидше, ніж комбінація "wc після grep", як у наступному прикладі:

Лістинг 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.0

Опція -c є гарним способомпідрахунку не лише через фактор швидкості. При використанні декількох файлів grep з опцією -c повертає окреме значення для кожного файлу, по одному на кожному рядку, тоді як напрямок виводу в wc дає загальний результатдля всіх файлів.

Однак цей приклад цікавий не лише з точки зору швидкодії – він ілюструє ще одну поширену помилку. Цей метод підрахунку надає тільки кількість рядків, у яких знайдено відповідності зразку- І добре, якщо це те, що ви шукаєте. Але у випадках, де рядки можуть мати кілька збігів із конкретним зразком, ці методи не дадуть реального числа відповідностей зразку. Для підрахунку числа збігів використовуйте wc. Для початку запустіть команду grep з опцією -o якщо ваша версія підтримує це. Ця опція виводить тількивідповідність зразку, по одному на кожен рядок, але не самий рядок. Її не можна використовувати разом з опцією -c , тому використовуйте wc -l для підрахунку числа рядків, як у прикладі:

Приклад хорошого методу роботи #8: Підрахунок числа збігів із зразком з grep
~ $ 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 14 грудня 14:26 archive.tar ~/tmp $

У цьому прикладі grep фільтрує рядки та виводить усі файли, в імені або даті зміни яких міститься 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 для пошуку за вмістом окремого файлу. Це абсолютно непотрібна втрата часу, тому що такі інструменти, 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.00s

Ця помилка допускається у багатьох випадках. Оскільки більшість інструментів отримують стандартне введенняу вигляді аргументу, використовуючи тире (-), навіть аргумент для використання cat для різноманітності численних файлів з stdin часто не є дійсним. Насправді необхідно виконати конкатенацію перед використанням catз однією з кількох опцій фільтрації.

Висновок: звикайте до хорошого

Ми розглянули кілька методів роботи у командному рядку. Погані звички уповільнюють роботу та часто призводять до непередбаченим помилкам. Ця стаття розповідає про 10 нових способів, які можуть допомогти вам позбутися багатьох найбільш поширених помилок. Звикайте до цих хороших методів та покращуйте свої навички роботи з командним рядком Unix.