Content from Знайомство з терміналом


Останнє оновлення 2025-03-10 | Редагувати цю сторінку

Огляд

Питання

  • Що таке командний термінал і навіщо його використовувати?

Цілі

  • Пояснити, як термінал пов’язаний з клавіатурою, екраном, операційною системою та програмами користувача.
  • Пояснити, коли та чому інтерфейси командного рядка слід використовувати замість графічних інтерфейсів.

Попередні знання

Люди та комп’ютери зазвичай взаємодіють багатьма різними способами, наприклад за допомогою клавіатури та миші, сенсорного екрану або системи розпізнавання мови. Найбільш поширений спосіб взаємодії з персональними комп’ютерами називається графічний інтерфейс користувача (GUI - graphical user interface). За допомогою такого інтерфейсу ми надаємо комп’ютеру інструкції, обираючи дію у меню за допомогою миші.

Хоча візуальна допомога графічного інтерфейсу користувача робить інтуїтивним його вивчення, такий спосіб надсилання інструкцій до комп’ютера дуже погано масштабується. Уявіть наступну задачу: для бібліографічного пошуку вам необхідно скопіювати третій рядок з тисячі вхідних файлів з тисячі різних директорій та вставити усе це в один файл. Використовуючи графічний інтерфейс, ви б не тільки клацали мишею на свому робочому місці декілька годин, але й могли б потенційно також внести помилку в процесі виконання монотонної задачі. Саме тут ми й скористаємося перевагами терміналу Unix. Термінал Unix - це одночасно інтерфейс командного рядка (англ. “Command-Line Interface”, CLI) та скриптова мова програмування, яка дозволяє виконувати подібні повторювані задачі автоматично та швидко. За допомогою відповідних команд термінал може повторювати задачі із певними змінами або без них стільки разів, скільки ми бажаємо. З використанням терміналу приклад задачі з бібліографічним пошуком може бути вирішений за секунди.

Термінал

Термінал - це програма, де користувач може вводити команди. За допомогою терміналу можна запускати складні програми, такі як програмне забезпечення для моделювання клімату, або прості команди, які створюють пустий каталог, командами, які займають лише один рядок. Найбільш популярним терміналом є Bash (the Bourne Again SHell, який отримав таку назву, тому що був розроблений на основі терміналу, написаного Стівеном Борном). Bash є терміналом за замовчуванням у більшості сучасних реалізацій Unix та у більшості пакетів, які надають Unix-подібні інструменти для Windows. Зауважте, що ‘Git Bash’ — це частина програмного забезпечення, яка дозволяє користувачам Windows використовувати інтерфейс, подібний до Bash, при взаємодії з Git.

Щоб користуватися терміналом, потрібно докласти певних зусиль і витратити час на його вивчення. У той час як графічний інтерфейс надає вам можливість вибору, команди терміналу не надаються автоматично, тому вам доведеться вивчити кілька команд, як нову лексику у мові, яку ви вивчаєте. Однак, на відміну від розмовної мови, невелика кількість “слів” (тобто команд) принесе вам неймовірну користь, і сьогодні ми розглянемо кілька найважливіших з них.

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

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

Отже, почнемо.

Коли термінал тільки відкрито, вам пропонується запит (англ. prompt), яке вказує на те, що термінал очікує на введення команд.

BASH

$

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

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

Зверніть увагу, що ваше запрошення може виглядати дещо інакше. Зокрема, більшість популярних середовищ оболонки за замовчуванням вказують ваше ім’я користувача та ім’я хоста перед ‘$’. Таке запрошення може виглядати, наприклад, так:

BASH

nelle@localhost $

Запрошення може містити навіть ще більше інформації. Не хвилюйтеся, якщо ваше запрошення - це не просто коротке $. Цей урок не залежить від цієї додаткової інформації, та вона також не повинна вам заважати. Єдиним важливим елементом, на якому слід зосередитися, є сам символ $, і ми побачимо пізніше, чому.

Отже, спробуймо нашу першу команду, ls (походить від англійського слова “listing”). Ця команда покаже зміст поточного каталогу:

BASH

$ ls

ВИХІД

Desktop     Downloads   Movies      Pictures
Documents   Library     Music       Public
Виноска

Команду не знайдено

Якщо термінал не може знайти програму, назву якої ви ввели, він виведе на екран наступне повідомлення про помилку:

BASH

$ ks

ВИХІД

ks: command not found

Це може трапитися, якщо при наборі команди була допущена помилка або якщо програма, що відповідає набраній команді, не встановлена.

Конвеєр Неллі: Типова Проблема


Неллі Немо (Nelle Nemo), морський біолог, щойно повернулась із шестимісячного дослідження Північного тихоокеанського кругообігу (North Pacific Gyre), де вона збирала зразки драглистих морських організмів у Великій тихоокеанській сміттєвій плямі. Вона має 1520 зразків, які вона пропускає через аналізатор, щоб виміряти відносну кількість 300 білків. Їй потрібно запустити ці 1520 файлів через уявну програму goostats.sh, яку вона успадкувала. Окрім цього величезного завдання, вона має написати результати до кінця місяця, щоб її робота могла з’явитися у спеціальному випуску Aquatic Goo Letters.

Якщо Неллі вирішить запустити goostats.sh вручну за допомогою графічного інтерфейсу, їй доведеться вибирати та відкривати файли 1520 разів. Якщо обробка одного файлу програмою goostats.sh триватиме 30 секунд, загальний процес вимагатиме більше ніж 12 годин уваги Неллі. За допомогою терміналу, Неллі може замість цього доручити своєму комп’ютеру цю рутинну роботу в той час, коли вона фокусує свою увагу на написанні статті.

У наступних кількох уроках будуть розглянуті шляхи, яким чином Неллі може цього досягти. Зокрема, на уроках пояснюється, як вона може використовувати термінал для запуску програми goostats.sh, використовуючи цикли для автоматизації повторюваних кроків введення імен файлів, щоб її комп’ютер міг працювати, поки вона пише свою наукову роботу.

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

Для того, щоб досягти своєї мети, Неллі необхідно знати, як:

  • перейти до файла/каталогу
  • створити файл/каталог
  • перевірити довжину файлу
  • з’єднати команди разом
  • отримати набір файлів
  • по черзі виконати дії над кожним файлом з набору
  • запустити скрипт, що містить розроблений нею конвеєр
Ключові моменти
  • Термінал - це програма, основним призначенням якої є читання команд і запуск інших програм.
  • У цьому уроці використовується Bash. Це термінал за замовчуванням у багатьох реалізаціях Unix.
  • Програми можна запускати у Bash шляхом введення команд у вікні командного рядка.
  • Основними перевагами терміналу є високе співвідношення кількості дій до кількості натискань клавіш, підтримка автоматизації повторюваних завдань, а також можливість доступу до віддалених машин.
  • Дуже важлива навичка при використанні оболонки - це вміння доречно використовувати текстові команди.

Content from Навігація по файловій системі


Останнє оновлення 2025-08-07 | Редагувати цю сторінку

Огляд

Питання

  • Як я можу пересуватися по файловій системі на моєму комп’ютері?
  • Як я можу переглянути файли та каталоги на своєму комп’ютері?
  • Як я можу вказати, де знаходиться файл або каталог на моєму комп’ютері?

Цілі

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

Частина операційної системи, яка відповідає за роботу з файлами та каталогами, називається файловою системою. Вона організує наші дані у файли, які зберігають інформацію, та каталоги (також відомі як ‘теки’), які містять файли або інші підкаталоги.

Для створення, перевірки, перейменування та видалення файлів і каталогів зазвичай використовується декілька команд. Щоб розглянути їх, перейдемо до нашого відкритого вікна терміналу.

По-перше, дізнаймося, де ми знаходимося, запустивши команду pwd (англ. ‘print working directory’ - надрукувати робочий каталог). Каталоги подібні до місцезнаходження - у будь-який момент, коли ми використовуємо термінал, ми знаходимося в одному місці, яке називається поточним робочим каталогом. Команди здебільшого читають та записують файли в поточний робочий каталог, тобто “сюди”. Тому дуже важливо розуміти де ви знаходитесь перед виконанням команди. Команда pwd покаже вам, де ви знаходитесь:

BASH

$ pwd

ВИХІД

/Users/nelle

У наведеному прикладі комп’ютер відповів /Users/nelle, що є домашнім каталогом Неллі:

Виноска

Варіації домашнього каталогу

Розташування домашнього каталогу виглядає по-різному в різних операційних системах. В Linux воно може виглядати як /home/nelle, а у Windows воно буде схоже на C:\Documents and Settings\nelle чи C:\Users\nelle. (Зауважте, що воно може виглядати дещо інакше для різних версій Windows.) У наведених нижче прикладах ми використовували результати у тому вигляді, у якому вони виглядають у macOS. Хоча вихідні дані Linux і Windows можуть дещо відрізнятися, загалом вони мають бути схожими.

Ми також припустимо, що ваша команда pwd повертає вашу домашню директорію користувача. Якщо команда pwd повертає щось інше, вам доведеться перейти у ваш домашній каталог за допомогою команди cd, інакше деякі команди в цьому уроці не будуть працювати належним чином. Дивіться Перегляд інших каталогів для додаткової інформації про команду cd.

Для того, щоб зрозуміти, що таке ‘домашній каталог’, розглянемо як організована файлова система в цілому. Для цього прикладу ми проілюструємо файлову систему на комп’ютері морського біолога Неллі. Після цього прикладу ви вивчатимете команди для дослідження власної файлової системи, яка буде побудована подібним чином, але не буде абсолютно ідентичною.

На комп’ютері Неллі файлова система виглядає так:

Файлова система складається з кореневого каталогу, який містить підкаталоги з назвами bin, data, users та tmp

Файлова система виглядає як перевернуте дерево. Найвищим каталогом є кореневий каталог, який містить усе інше. Ми посилаємося на нього за допомогою символу скісної риски / (зауважте, що він є першим символом у рядку /Users/nelle).

Усередині цього каталогу є кілька інших каталогів: bin (в якому зберігаються певні вбудовані програми), data (для різноманітних файлів даних), Users (де знаходяться особисті директорії користувачів), tmp (для файлів тимчасового зберігання) та інші.

Ми знаємо, що наш поточний робочий каталог /Users/nelle зберігається всередині каталогу /Users, тому що /Users є першою частиною його імені. Відповідно, нам відомо, що каталог /Users зберігається всередині кореневої директорії /, бо його ім’я розпочинається з символу /.

Виноска

Символи скісної риски

Зверніть увагу, що символ / має два значення. Коли він з’являється на початку назви файлу чи каталогу, це посилання на кореневу директорію. Коли він використовується всередині шляху, це лише роздільник.

На комп’ютері Неллі, у каталозі /Users є підкаталог для кожного користувача з обліковим записом, наприклад: для її колег imhotep та larry.

Як і інші каталоги, домашні каталоги є підкаталогами "/Users", наприклад "/Users/imhotep", "/Users/larry" або "/Users/nelle"

Файли користувача imhotep зберігаються в каталозі /Users/imhotep, користувача larry - в /Users/larry, і Неллі - в /Users/nelle. Оскільки саме Неллі є користувачем у наших прикладах, тому ми отримуємо /Users/nelle як наш домашній каталог. Зазвичай, коли ви відкриваєте нове вікно терміналу, ви опиняєтесь у своєму домашньому каталозі.

Тепер розглянемо команду, яка дозволить нам бачити вміст нашої власної файлової системи. Ми можемо побачити, що знаходиться у нашому домашньому каталозі, запустивши ls:

BASH

$ ls

ВИХІД

Applications Documents    Library      Music        Public
Desktop      Downloads    Movies       Pictures

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

ls друкує назви файлів і каталогів у поточному каталозі. Ми можемо зробити його вивід більш зрозумілим за допомогою опції -F, яка вказує ls класифікувати вивід, додаючи маркер до імен файлів і каталогів, щоб вказати, що вони собою являють:

  • символ / наприкінці імені вказує на те, що це каталог
  • символ @ вказує на посилання
  • символ * вказує на виконуваний файл

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

BASH

$ ls -F

ВИХІД

Applications/ Documents/    Library/      Music/        Public/
Desktop/      Downloads/    Movies/       Pictures/

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

Виноска

Як очистити термінал

Якщо екран стає занадто захаращеним, ви можете очистити термінал за допомогою команди clear. Ви все ще можете отримати доступ до попередніх команд за допомогою клавіш та для переміщення по рядках, або за допомогою прокрутки у вашому терміналі.

Отримання допомоги

У ls є багато інших опцій. Існує два поширених способи дізнатися, як використовувати команду і які параметри вона приймає — залежно від вашого середовища, ви можете виявити, що працює лише один із цих способів:

  1. Ми можемо передати команді опцію --help (доступну в Linux і Git Bash), наприклад:

BASH

$ ls --help
  1. Ми можемо переглянути інструкцію до використання команди за допомогою man (доступної на Linux і macOS), наприклад:

BASH

$ man ls

Далі ми роздивимось обидва способи.

Виноска

Довідка для вбудованих команд

Деякі команди вбудовано в оболонку Bash, а не існують як окремі програми у файловій системі. Одним із прикладів є команда cd (зміна каталогу). Якщо після команди man cd ви отримуєте повідомлення на кшталт No manual entry for cd, спробуйте натомість help cd. За допомогою команди help ви можете отримати інформацію про використання вбудованих команд Bash.

Опція `–help’

Більшість команд bash і програм, написаних людьми для запуску з bash, підтримують опцію --help, яка виводить додаткову інформацію про те, як користуватися відповідною командою або програмою.

BASH

$ ls --help

ВИХІД

Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if neither -cftuvSUX nor --sort is specified.

Mandatory arguments to long options are mandatory for short options, too.
  -a, --all                  do not ignore entries starting with .
  -A, --almost-all           do not list implied . and ..
      --author               with -l, print the author of each file
  -b, --escape               print C-style escapes for nongraphic characters
      --block-size=SIZE      scale sizes by SIZE before printing them; e.g.,
                               '--block-size=M' prints sizes in units of
                               1,048,576 bytes; see SIZE format below
  -B, --ignore-backups       do not list implied entries ending with ~
  -c                         with -lt: sort by, and show, ctime (time of last
                               modification of file status information);
                               with -l: show ctime and sort by name;
                               otherwise: sort by ctime, newest first
  -C                         list entries by columns
      --color[=WHEN]         colorize the output; WHEN can be 'always' (default
                               if omitted), 'auto', or 'never'; more info below
  -d, --directory            list directories themselves, not their contents
  -D, --dired                generate output designed for Emacs' dired mode
  -f                         do not sort, enable -aU, disable -ls --color
  -F, --classify             append indicator (one of */=>@|) to entries
...        ...        ...
Виноска

Коли використовувати короткі або довгі опції

Коли існують як короткі, так і довгі опції:

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

Непідтримувані параметри командного рядка

Якщо ви спробуєте використати параметр, який не підтримується терміналом, ls та інші команди зазвичай виводитимуть повідомлення про помилку, схоже на:

BASH

$ ls -j

ПОМИЛКА

ls: invalid option -- 'j'
Try 'ls --help' for more information.

Команда man

Інший спосіб дізнатися про ls - ввести

BASH

$ man ls

Ця команда виведе у вашому терміналі сторінку з описом команди ls та її опцій.

Для навігації сторінками man ви можете використовувати і для переміщення по рядках, або спробувати b і Spacebar для переходу вгору і вниз на цілу сторінку. Для пошуку символу або слова на сторінках man, використовуйте клавішу / та слідом введіть символ або слово, яке ви шукаєте. Іноді пошук може призвести до кількох результатів. У такому випадку ви можете переміщатися між результатами за допомогою клавіш N (для переходу вперед) та Shift+N (для переходу назад).

Щоб вийти зі сторінок man, натисніть q.

Виноска

Сторінки з інструкціями в Інтернеті

Звісно, є й третій спосіб отримати доступ до довідки для команд: пошук в інтернеті за допомогою веббраузера. Якщо ви скористаєтеся пошуком в Інтернеті, додання до запиту фрази unix man page дозволить отримати більш доречні результати.

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

Вправа

Вивчення інших опцій ls

Ви також можете використовувати декілька опцій одночасно. Що робить команда ls при використанні з опцією -l? А якщо ви використовуєте -l та -h одночасно?

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

Опція -l змушує ls використовувати довгий (англ. long) формат виводу, показуючи не лише назви файлів/директорій, але й додаткову інформацію, таку як розмір файлу і час його останньої модифікації. Якщо ви використовуєте як -h, так і -l, це зробить виведення розміру файлу у більш зрозумілому людині вигляді (“human readable”), тобто покаже щось на кшталт 5.3K замість 5369.

Вправа

Виведення у зворотному хронологічному порядку

За замовчуванням ls виводить вміст каталогу в алфавітному порядку за іменами елементів. Команда ls -t перелічує елементи за часом останньої зміни, а не за алфавітом. Команда ls -r виводить вміст каталогу у зворотному порядку. Який файл буде показано останнім при комбінації опцій -t і -r? Підказка: Вам потрібно скористатися опцією -l, щоб переглянути дати останніх змін.

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

Перегляд інших каталогів

Ми можемо використовувати ls не лише у поточному робочому каталозі, але й для виведення вмісту іншого каталогу. Подивимося на наш каталог Desktop (робочий стіл), виконавши ls -F Desktop, тобто, команду ls з опцією -F і аргументом Desktop. Аргумент Desktop повідомляє ls, що ми хочемо отримати список чогось іншого, ніж наш поточний робочий каталог:

BASH

$ ls -F Desktop

ВИХІД

shell-lesson-data/

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

На виході ви маєте отримати список усіх файлів і підкаталогів у вашому каталозі Desktop, включно з каталогом shell-lesson-data, який ви завантажили за посиланням під час налаштувань для цього уроку. (На більшості систем вміст каталогу Desktop в терміналі можна побачити на екрані у вигляді піктограм, якщо згорнути або закрити усі вікна у графічному інтерфейсі користувача. Подивіться, чи це ваш випадок.)

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

Тепер, коли ми знаємо, що каталог shell-lesson-data знаходиться у каталозі Desktop, ми можемо зробити дві речі.

По-перше, ми можемо переглянути його вміст, використовуючи ту ж стратегію, що і раніше, передавши ім’я каталогу в ls:

BASH

$ ls -F Desktop/shell-lesson-data

ВИХІД

exercise-data/  north-pacific-gyre/

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

Командою для зміни каталогів є cd, після якої йде назва каталогу, до якого ви хочете перейти. Це оновить поточний робочий каталог. cd означає ‘змінити каталог’ (англ. ‘change directory’), що трохи вводить в оману. Команда не змінює сам каталог; вона змінює поточний робочий каталог у терміналі. Іншими словами, вона змінює налаштування терміналу щодо того, в якому каталозі ми знаходимося. Команда cd подібна до подвійного клацання по каталогу в графічному інтерфейсі, щоб потрапити до нього.

Припустимо, нам треба перейти до каталогу exercise-data, який ми бачили вище. Ми можемо скористатися наступною серією команд, щоб дістатися туди:

BASH

$ cd Desktop
$ cd shell-lesson-data
$ cd exercise-data

Ці команди перемістять нас з домашнього каталогу до Desktop, потім до shell-lesson-data, а потім до exercise-data. Ви помітите, що команда cd нічого не виводить. Це нормально. Багато команд терміналу нічого не виводять на екран після успішного виконання. Але якщо ми виконаємо pwd після неї, то побачимо, що зараз ми знаходимося у /Users/nelle/Desktop/shell-lesson-data/exercise-data.

Тепер, якщо ми виконаємо команду ls -F без аргументів, вона виведе вміст /Users/nelle/Desktop/shell-lesson-data/exercise-data, тому що саме там ми зараз знаходимося:

BASH

$ pwd

ВИХІД

/Users/nelle/Desktop/shell-lesson-data/exercise-data

BASH

$ ls -F

ВИХІД

alkanes/  animal-counts/  creatures/  numbers.txt  writing/

Тепер ми знаємо, як рухатися вниз по дереву каталогів (тобто, як перейти до підкаталогу), але як рухатися вгору (тобто, як вийти з каталогу і перейти до його батьківського каталогу)? Ми можемо спробувати наступне:

BASH

$ cd shell-lesson-data

ПОМИЛКА

-bash: cd: shell-lesson-data: No such file or directory

Але ми отримуємо помилку! Чому?

За допомогою поки що знайомих нам методів, cd може бачити лише підкаталоги у вашому поточному каталозі. Існують різні способи перегляду батьківських каталогів; ми почнемо з найпростішого.

У терміналі є скорочення для переходу на один рівень каталогу вгору. Це працює наступним чином:

BASH

$ cd ..

.. - це спеціальне ім’я каталогу, що означає “каталог, що містить поточний”, або більш стисло, батько поточного каталогу. Звичайно, якщо ми запустимо pwd після виконання cd .., ми знову у /Users/nelle/Desktop/shell-lesson-data:

BASH

$ pwd

ВИХІД

/Users/nelle/Desktop/shell-lesson-data

Спеціальний каталог .. зазвичай не з’являється, коли ми запускаємо ls. Якщо ми хочемо побачити його, ми можемо додати опцію -a до ls -F:

BASH

$ ls -F -a

ВИХІД

./  ../  exercise-data/  north-pacific-gyre/

-a означає ‘показати все’ (англ. show all) (включно з прихованими файлами); ця опція змушує ls показувати нам імена файлів і каталогів, які починаються з ., наприклад, .. (яке, якщо ми знаходимося у /Users/nelle, вказує на каталог /Users). Як ви можете бачити, команда також показує ще один спеціальний каталог, який називається ., що означає ‘поточний робочий каталог’. Може здатися, що це дещо надлишково - мати для нього ім’я, але незабаром ми побачимо, як воно може бути використано.

Зауважте, що у більшості інструментів командного рядка можна комбінувати декілька параметрів за допомогою одного - і без пробілів між параметрами: ls -F -a є еквівалентним до ls -Fa.

Виноска

Інші приховані файли

Крім прихованих каталогів .. та ., ви також можете побачити файл з назвою .bash_profile. Цей файл зазвичай містить конфігурацію терміналу. Ви також можете зустріти інші файли й каталоги, які починаються з символу .. Зазвичай це конфігураційні файли та каталоги, які використовуються різними програмами на вашому комп’ютері для налаштування. Префікс . використовується для того, щоб ці конфігураційні файли не захаращували термінал, коли використовується стандартна команда ls.

Ці три команди є основними командами для навігації по файловій системі на вашому комп’ютері: pwd, ls і cd. Розгляньмо деякі варіації цих команд. Що станеться якщо ви введете команду cd саму по собі, не зазначаючи каталог?

BASH

$ cd

Як перевірити, що сталося? Команда pwd дає нам відповідь!

BASH

$ pwd

ВИХІД

/Users/nelle

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

Спробуємо повернутися до каталогу exercise-data. Минулого разу ми використовували три команди, але насправді ми можемо поєднати перелік каталогів для переходу до каталогу exercise-data за один крок:

BASH

$ cd Desktop/shell-lesson-data/exercise-data

Переконайтеся, що ми перемістилися в потрібне місце, виконавши pwd і ls -F.

Щоб перейти на один рівень вище від каталогу даних, ми можемо використати cd ... Але існує інший спосіб переміщення до будь-якого каталогу, незалежно від вашого поточного розташування.

Дотепер, ми використовували відносні шляхи для вказування назви каталогів або навіть шляхів до каталогів (як описано вище). Він повідомляє таким командам, як ls або cd, знайти каталог на основі нашої поточної позиції у файловій системі, а не з кореня файлової системи.

Однак ми також можемо використовувати абсолютні шляхи, які вказують повне розташування каталогу, починаючи від кореневого каталогу, який позначається символом скісної риски (/). Символ / на початку абсолютного шляху вказує комп’ютеру слідувати шляхом від кореня файлової системи, тому шлях інтерпретується однаково, незалежно від нашого поточного каталогу.

Це дає змогу перейти до каталогу shell-lesson-data з будь-якого місця у файловій системі (у тому числі з каталогу exercise-data). Щоб знайти абсолютний шлях ми можемо скористатися pwd, а потім витягти потрібний нам фрагмент, щоб перейти до shell-lesson-data.

BASH

$ pwd

ВИХІД

/Users/nelle/Desktop/shell-lesson-data/exercise-data

BASH

$ cd /Users/nelle/Desktop/shell-lesson-data

Виконайте pwd і ls -F, щоб переконатися, що ми знаходимося в потрібному каталозі.

Виноска

Ще два скорочення

Термінал інтерпретує символ тильди (~) на початку шляху як “домашній каталог поточного користувача”. Наприклад, якщо домашнім каталогом користувача Неллі є каталог /Users/nelle, то ~/data еквівалентно /Users/nelle/data. Це працює лише у випадку, якщо це перший символ у шляху: here/there/~/elsewhere не єhere/there/Users/nelle/elsewhere.

Іншим скороченням є символ - (тире). cd інтерпретує - як попередній каталог, у якому я був, що є швидше, ніж запам’ятовувати, а потім набирати повний шлях. Це дуже ефективний спосіб переміщення між двома каталогами - тобто, якщо ви виконаєте cd - двічі, це повертає вас до початкового каталогу.

Різниця між cd .. і cd - полягає в тому, що перший переміщується на один рівень вище в ієрархії каталогів, а другий повертає вас назад.


Спробуйте! Спочатку перейдіть до ~/Desktop/shell-lesson-data (ви вже маєте бути там).

BASH

$ cd ~/Desktop/shell-lesson-data

Потім cd у каталог exercise-data/creatures

BASH

$ cd exercise-data/creatures

Тепер, якщо ви виконаєте

BASH

$ cd -

ви побачите, що повернулися до ~/Desktop/shell-lesson-data. Запустіть cd - ще раз і ви повернетесь до ~/Desktop/shell-lesson-data/exercise-data/creatures

Вправа

Абсолютні та відносні шляхи

Якщо Неллі зараз знаходиться в /Users/nelle/data, то яка з наведених нижче команд дозволить їй повернутися до її домашнього каталогу /Users/nelle?

  1. cd .
  2. cd /
  3. cd /home/nelle
  4. cd ../..
  5. cd ~
  6. cd home
  7. cd ~/data/..
  8. cd
  9. cd ..
  1. Ні: скорочення . означає поточний каталог.

  2. Ні: скорочення / означає кореневий каталог.

  3. Ні: домашнім каталогом Неллі є /Users/nelle.

  4. Ні: ця команда переходить на два рівні вгору, тобто до /Users.

  5. Так: символ ~ позначає домашній каталог користувача, у цьому випадку /Users/nelle.

  6. Ні: ця команда виконає перехід до каталогу home у поточному каталозі, якщо він існує.

  7. Так: надмірно складна, але правильна.

  8. Так: скорочення для повернення до домашнього каталогу користувача.

  9. Так: підіймається на один рівень вище в структурі каталогів.

Вправа

Завдання відносного шляху

Використовуючи наведену нижче схему файлової системи, якщо pwd показує /Users/thing, що покаже команда ls -F ../backup?

  1. ../backup: No such file or directory (не існує такого файлу або каталогу)
  2. 2012-12-01 2013-01-08 2013-01-27
  3. 2012-12-01/ 2013-01-08/ 2013-01-27/
  4. original/ pnas_final/ pnas_sub/
Дерево каталогів під каталогом Users, де "/Users" містить каталоги "backup" та "thing"; "/Users/backup" містить "original", "pnas_final" та "pnas_sub"; "/Users/thing" містить "backup"; та "/Users/thing/backup" містить "2012-12-01", "2013-01-08" та "2013-01-27"
  1. Ні: у каталозі/Users існує підкаталог backup.

  2. Ні: це вміст каталогу Users/thing/backup, але за допомогою .. ми просили піднятися на один рівень вище.

  3. Ні: див. попереднє пояснення.

  4. Так: ../backup/ вказує на /Users/backup/.

Вправа

Розуміння команди ls

Звертаючись до діаграми файлової системи нижче, якщо pwd повертає /Users/backup, а параметр -r у команді ls змінює порядок виведення результатів, яка (які) команда (команди) призведе до наступного результату:

ВИХІД

pnas_sub/ pnas_final/ original/
Дерево каталогів під каталогом Users, де "/Users" містить каталоги "backup" та "thing"; "/Users/backup" містить "original", "pnas_final" та "pnas_sub"; "/Users/thing" містить "backup"; та "/Users/thing/backup" містить "2012-12-01", "2013-01-08" та "2013-01-27"
  1. ls pwd
  2. ls -r -F
  3. ls -r -F /Users/backup
  1. Ні: pwd не є назвою каталогу.

  2. Так: команда ls без аргументу перелічує файли й каталоги у поточному каталозі.

  3. Так: чітко використовує абсолютний шлях.

Загальний синтаксис команд терміналу


Ми вже познайомилися з командами, опціями та аргументами, але, можливо, буде корисно формалізувати деяку термінологію.

Розглянемо команду нижче як приклад і розберемо її на складові частини:

BASH

$ ls -F /
Загальний синтаксис команди терміналу

ls - це команда, з опцією -F та аргументом /. Ми вже зустрічалися з опціями, які починаються з одного тире (-), відомі як короткі варіанти, або двох тире (--), відомі як довгі варіанти. [Опції] змінюють поведінку команди, а [аргументи] вказують команді, над чим вона має працювати (наприклад, над файлами й каталогами). Іноді опції та аргументи називають параметрами. Команда може сприймати кілька параметрів і аргументів, але вона не завжди вимагає їх.

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

Кожна частина відокремлюється пробілами. Якщо ви пропустите пробіл між ls і -F, термінал шукатиме команду з назвою ls-F, якої не існує. Також, параметри чутливі до регістру. Наприклад, ls -s покаже розміри файлів та каталогів поряд з їхніми назвами., а ls -S відсортує файли та каталоги за розміром, як показано нижче:

BASH

$ cd ~/Desktop/shell-lesson-data
$ ls -s exercise-data

ВИХІД

total 28
 4 animal-counts   4 creatures  12 numbers.txt   4 alkanes   4 writing

Зверніть увагу, що розміри, які повертає команда ls -s, подано у блоках. Оскільки вони визначаються по-різному для різних операційних систем, ви можете отримати не такі значення, як у прикладі.

BASH

$ ls -S exercise-data

ВИХІД

animal-counts  creatures  alkanes  writing  numbers.txt

Зібравши все це разом, команда ls -F / вище дасть нам список файлів і каталогів у кореневому каталозі /. Нижче наведено приклад результату, який ви можете отримати від цієї команди:

BASH

$ ls -F /

ВИХІД

Applications/         System/
Library/              Users/
Network/              Volumes/

Конвеєр Неллі: Організація файлів

Знаючи так багато про файли та каталоги, Неллі готова впорядкувати файли, які створить машина для аналізу білків.

Вона створює каталог під назвою north-pacific-gyre (щоб нагадати собі, звідки взялися дані), який міститиме файли даних з аналітичної машини та її скрипти для обробки даних.

Кожному фізичному зразку присвоюється унікальний десятисимвольний ідентифікатор, наприклад ‘NENE01729A’, згідно з затвердженими в лабораторії правилами. Оскільки цей ідентифікатор вона використовує у своєму журналі для документування таких деталей, як місцезнаходження, часу і глибини, то вона додає його до імен своїх файлів даних. Оскільки результат роботи аналізатора є звичайним текстом, вона назве свої файли NENE01729A.txt, NENE01812A.txt і так далі. Усі 1520 файлів буде збережено в одному каталозі.

Тепер у її поточному каталозі shell-lesson-data, Неллі може побачити, які файли вона має за допомогою цієї команди:

BASH

$ ls north-pacific-gyre/

Ця команда вимагає багато друку, але Неллі може мінімізувати зусилля, використовуючи табуляцію, що дозволяє терміналу автоматично завершувати команди та імена файлів. Якщо вона набере:

BASH

$ ls nor

а потім натисне клавішу Tab (клавішу табуляції на її клавіатурі), то термінал автоматично доповнить назву каталогу для неї:

BASH

$ ls north-pacific-gyre/

Повторне натискання клавіші Tab нічого не дасть, оскільки існує декілька варіантів; якщо натиснути Tab двічі, буде показано список усіх відповідних файлів.

Якщо Неллі потім натисне щеG і знову Tab, оболонка додасть ‘goo’, оскільки всі файли, що починаються з ‘g’, мають спільні перші три символи ‘goo’.

BASH

$ ls north-pacific-gyre/goo

Щоб побачити всі ці файли, вона може натиснути клавішу Tab ще двічі.

BASH

ls north-pacific-gyre/goo goodiff.sh goostats.sh

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

Ключові моменти
  • Файлова система відповідає за керування інформацією на диску.
  • Інформація зберігається у файлах, які зберігаються в каталогах (теках).
  • Каталоги також можуть зберігати інші підкаталоги, які таким чином створюють дерево каталогів.
  • Команда pwd виводить поточний робочий каталог користувача.
  • Команда ls [path] виводить список з певного файлу або каталогу; команда ls сама по собі виводить список поточного робочого каталогу.
  • Команда cd [path] змінює поточний робочий каталог.
  • Більшість команд приймають параметри, які починаються з одного символу -.
  • Назви каталогів в шляху розділяються символами / в Unix, але \ в Windows.
  • Символ / сам по собі зазначає кореневий каталог усієї файлової системи.
  • Абсолютний шлях вказує на розташування відносно кореня файлової системи.
  • Відносний шлях вказує на розташування, починаючи з поточного каталогу.
  • Символ . сам по собі означає ‘поточний каталог’; .. означає ‘батьківський каталог’ (той, що знаходиться над поточним каталогом).

Content from Робота з файлами та каталогами


Останнє оновлення 2025-08-28 | Редагувати цю сторінку

Огляд

Питання

  • Як я можу створювати, копіювати та видаляти файли і каталоги?
  • Як я можу редагувати файли?

Цілі

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

Створення каталогів


Тепер ми знаємо, як досліджувати файли та каталоги, але як їх створювати?

У цьому уроці ми дізнаємося про створення та переміщення файлів і каталогів на прикладі каталогу exercise-data/writing.

Крок перший: подивимось, де ми знаходимося і що вже маємо

Ми все ще маємо бути у каталозі shell-lesson-data на Робочому столі (англ. Desktop), що ми можемо перевірити за допомогою:

BASH

$ pwd

ВИХІД

/Users/nelle/Desktop/shell-lesson-data

Далі ми перейдемо до каталогу exercise-data/writing і подивимося, що у ньому міститься:

BASH

$ cd exercise-data/writing/
$ ls -F

ВИХІД

haiku.txt LittleWomen.txt

Створення каталогу

Створимо новий каталог з назвою thesis за допомогою команди mkdir thesis (яка не має виводу):

BASH

$ mkdir thesis

Як ви можете здогадатися з її назви, команда mkdir означає ‘створити каталог’ (англ. ‘make directory’). Оскільки thesis є відносним шляхом (тобто не має початкової косої риски, як /what/ever/thesis), новий каталог буде створено у поточному робочому каталозі:

BASH

$ ls -F

ВИХІД

haiku.txt  LittleWomen.txt  thesis/

Оскільки ми щойно створили каталог thesis, у ньому ще нічого немає:

BASH

$ ls -F thesis

Зауважте, що команда mkdir не тільки створює окремі каталоги по одному за раз. Параметр -p дозволяє команді mkdir створювати каталог із вкладеними підкаталогами за одну операцію:

BASH

$ mkdir -p ../project/data ../project/results

Параметр -R з командою ls покаже усі вкладені підкаталоги у каталозі. Скористаймось ls -FR для рекурсивного зображення нової ієрархії каталогів, яку ми щойно створили у каталозі project:

BASH

$ ls -FR ../project

ВИХІД

../project/:
data/  results/

../project/data:

../project/results:
Виноска

Два способи зробити одне й те саме

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

Виноска

Доречні імена для файлів і каталогів

Використання надто складних імен для файлів і каталогів може ускладнити роботу в командному рядку. Ось кілька корисних порад щодо вибору ефективних імен.

  1. Не використовуйте пробіли.

Пробіли можуть зробити назву більш змістовною, але оскільки вони використовуються для відокремлення аргументів у командному рядку, краще уникати їх у назвах файлів і каталогів. Ви можете використовувати - або _ (наприклад, north-pacific-gyre/ замість north pacific gyre/). Щоб перевірити це, спробуйте набрати mkdir north pacific gyre і подивіться, який каталог (або каталоги!) буде створено, перевірив це за допомогою ls -F.

  1. Не починайте назву з - (тире).

Команди розглядають назви, що починаються з -, як опції.

  1. Використовуйте літери, цифри, . (крапку), - (тире) і _ (підкреслення).

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

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

Створення текстового файлу

Перейдімо до каталогу thesis за допомогою cd, а потім запустимо текстовий редактор Nano та створимо файл з назвою draft.txt:

BASH

$ cd thesis
$ nano draft.txt
Виноска

Який редактор використовувати?

Коли ми говоримо, що ‘nano - це текстовий редактор’, ми дійсно маємо на увазі ‘текстовий’. У ньому неможливо переглядати або редагувати таблиці, зображення чи будь-які інші зручні для сприйняття людиною дані. Ми використовуємо його у прикладах, оскільки це один із найпростіших текстових редакторів. Однак, через це він може виявитися недостатньо потужним або гнучким для складніших завдань, які вам потрібно буде виконати після завершення цього семінару. У системах Unix (таких як Linux та macOS), багато програмістів використовують [Emacs] (https://www.gnu.org/software/emacs/) чи Vim (обидва вимагають більше часу на вивчення), або графічний редактор, такий як Gedit чи VScode. У Windows, можливо, ви захочете скористатися Notepad++. Операційна система Windows також має вбудований редактор з назвою notepad, який можна запустити з командного рядка так само, як і nano для цього семінару.

Незалежно від того, яким редактором ви користуєтеся, вам потрібно знати, де він шукає і зберігає файли. Якщо ви запускаєте його з термінала, він (імовірно) використовуватиме ваш поточний робочий каталог як розташування за замовчуванням. Однак, якщо ви використовуєте меню “Пуск” вашого комп’ютера, файли за замовчуванням можуть зберігатися замість цього на робочому столі або в каталозі “Документи” (Documents). Ви можете змінити це, перейшовши до іншого каталогу під час першого виконання команди “Зберегти як…” (“Save As…”).

Наберемо кілька рядків тексту.

{alt=“Скриншот текстового редактора nano в дії з текстом”У минулому це було - публікуй чи зникни, а наразі стало - ділися та процвітай”}

Як тільки ми будемо задоволені нашим текстом, нам треба використати комбінацію Ctrl+O (утримуючи клавішу Ctrl or Control, натисніть клавішу O), щоб зберегти наші дані на диск. Потім нам буде запропоновано вказати ім’я файлу, у якому зберігатиметься наш текст. Натисніть Return, щоб прийняти запропоновану за замовчуванням назву draft.txt.

Як тільки файл було збережено, скористаємось комбінацією клавіш Ctrl+X, щоб вийти з редактора і повернутися до термінала.

Виноска

Клавіша Control, Ctrl або ^

Клавіші Control також називається клавішею ‘Ctrl’. Існує декілька способів, якими може бути описане використання клавіші Control. Наприклад, ви можете побачити вказівку натиснути клавішу Control і, утримуючи її натиснутою, потім натиснути клавішу X, описану будь-яким з наступних способів:

  • Control-X
  • Control+X
  • Ctrl-X
  • Ctrl+X
  • ^X
  • C-x

У nano, у нижній частині екрана ви побачите ^G Get Help ^O WriteOut. Це означає, що ви можете скористатися Control-G для отримання довідки й Control-O для збереження вашого файлу.

Після завершення роботи команда nano не залишає жодних даних на екрані, але ls тепер показує, що ми створили файл з назвою draft.txt:

BASH

$ ls

ВИХІД

draft.txt
Вправа

Створення файлів іншим способом

Ми побачили, як створювати текстові файли за допомогою редактора nano. Тепер спробуйте виконати наступну команду:

BASH

$ touch my_file.txt
  1. Що зробила команда touch? Якщо ви відкриєте поточний каталог у файловому провіднику, чи видно в ньому цей файл?

  2. Скористуйтеся ls -l для перегляду файлів. Який розмір має файл my_file.txt?

  3. У яких випадках доцільно створювати файл саме таким чином?

  1. Команда touch створює новий файл з назвою my_file.txt у вашому поточному каталозі. Щоб переконатися, що файл створено, скористайтеся командою ls. Файл my_file.txt також можна переглянути у вашому графічному провіднику файлів.

  2. Коли ви перевіряєте файл за допомогою ls -l, зверніть увагу, що розмір my_file.txt — 0 байт. Це означає, що файл порожній. Якщо відкрити його в редакторі, ви не знайдете в ньому жодного вмісту.

  3. Іноді програми не генерують вихідні файли автоматично, а потребують, щоб порожні файли були створені заздалегідь. Потім під час виконання програма шукає наявний файл, щоб заповнити його своїми даними. За допомогою команди touch можна ефективно створити порожній текстовий файл для подальшого використання такими програмами.

Обговорення

Створення файлів іншим способом (continued)

Щоб уникнути плутанини пізніше, радимо видалити створений файл перед продовженням епізоду, інакше майбутні результати можуть відрізнятися від наведених в уроці. Для цього скористайтеся наступною командою:

BASH

$ rm my_file.txt
Виноска

Що ховається в імені?

Ви, мабуть, помітили, що всі файли Неллі називаються ‘щось крапка щось’, і у цій частині уроку ми завжди використовували розширення .txt. Це лише умовність: ми можемо назвати файл mythesis або майже як завгодно. Однак, більшість людей здебільшого використовують назви, що складаються з двох частин для того, щоб допомогти їм (і їхнім програмам) розрізняти різні типи файлів. Друга частина такого імені називається розширенням файлу і вказує тип даних у файлі: .txt вказує на простий текстовий файл, .pdf вказує на PDF-документ, .cfg - це конфігураційний файл з параметрами для тієї чи іншої програми, .png - зображення у форматі PNG, і так далі.

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

Якщо ви назвете зображення кита у форматі PNG як whale.mp3, це не перетворить його якимось чарівним чином на запис пісні кита, хоча це може змусити операційну систему спробувати відкрити його за допомогою музичного плеєра. У цьому випадку, якщо хтось двічі клацне на файлі whale.mp3 у файловому провіднику, музичний програвач автоматично (і помилково) спробує відкрити файл whale.mp3.

Переміщення файлів і каталогів


Повернемося до каталогу shell-lesson-data/exercise-data/writing:

BASH

$ cd ~/Desktop/shell-lesson-data/exercise-data/writing

У нашому каталозі thesis є файл draft.txt, з не надто інформативною назвою, тому змінімо назву файлу за допомогою команди mv, що є скороченням від ‘move’ (з англ. - ‘переміщати’):

BASH

$ mv thesis/draft.txt thesis/quotes.txt

Перший аргумент говорить mv, що ми “переміщаємо”, а другий - куди саме. У цьому випадку ми переміщуємо thesis/draft.txt до thesis/quotes.txt, що має той самий ефект, що і перейменування файлу. Після цього ls підтверджує, що thesis тепер містить один файл з назвою quotes.txt:

BASH

$ ls thesis

ВИХІД

quotes.txt

Слід бути обережним, вказуючи ім’я цільового файлу, оскільки mv приховано перезапише будь-який наявний файл з такою самою назвою, а це може призвести до втрати даних. За замовчуванням mv не запитуватиме підтвердження перед перезаписом файлів. Однак додатковий параметр mv -i (або mv --interactive) змусить mv запросити таке підтвердження.

Зверніть увагу, що mv також працює з каталогами.

Перемістимо quotes.txt до поточного робочого каталогу. Знову скористаємося mv, але цього разу ми використаємо лише назву каталогу як другий аргумент щоб повідомити mv, що ми хочемо зберегти назву файлу, але перемістити файл у нове місце. (Ось чому команда називається ‘перемістити’.) У цьому випадку ми використовуємо спеціальну назву . поточного каталогу, про яку ми згадували раніше.

BASH

$ mv thesis/quotes.txt .

Наслідком цього буде переміщення файлу з початкового каталогу до поточного робочого каталогу. Тепер ls показує нам, що каталог thesis` порожній:

BASH

$ ls thesis

ВИХІД

$

Крім того, ми можемо переконатися, що файл quotes.txt більше не присутній у каталозі thesis, спробувавши показати інформацію про нього:

BASH

$ ls thesis/quotes.txt

ПОМИЛКА

ls: cannot access 'thesis/quotes.txt': No such file or directory

Команда ls, якщо вказати ім’я файлу або каталогу як аргумент, виводить лише список запитуваних файлів або каталогів. Якщо вказаного файлу не існує, термінал поверне помилку — як ми вже бачили раніше. Таким чином ми можемо перевірити, що файл quotes.txt тепер знаходиться у поточному каталозі:

BASH

$ ls quotes.txt

ВИХІД

quotes.txt
Вправа

Переміщення файлів до нового каталогу

Після виконання наступних команд Джеймі зрозуміла, що помістила файли sucrose.dat та maltose.dat не до того каталогу. Файли потрібно було помістити у каталог raw.

BASH

$ ls -F
 analyzed/ raw/
$ ls -F analyzed
fructose.dat glucose.dat maltose.dat sucrose.dat
$ cd analyzed

Заповніть пропуски, щоб перемістити ці файли до каталогу raw/ (тобто туди, куди вона забула їх помістити)

BASH

$ mv sucrose.dat maltose.dat ____/____

BASH

$ mv sucrose.dat maltose.dat ../raw

Пам’ятайте, що .. вказує на батьківський каталог (тобто на каталог рівнем вище поточного), а . вказує на поточний каталог.

Копіювання файлів і каталогів


Команда cp працює майже так само, як і mv, але замість переміщення копіює файл. Ми можемо перевірити результат за допомогою ls з двома шляхами у ролі параметрів, адже ls та більшість команд Unix здатні приймати декілька аргументів одночасно:

BASH

$ cp quotes.txt thesis/quotations.txt
$ ls quotes.txt thesis/quotations.txt

ВИХІД

quotes.txt   thesis/quotations.txt

Ми також можемо скопіювати каталог і весь його вміст за допомогою рекурсивної опції -r, наприклад, для створення резервної копії каталогу:

BASH

$ cp -r thesis thesis_backup

Ми можемо перевірити результат, переглянувши вміст каталогів thesis та thesis_backup:

BASH

$ ls thesis thesis_backup

ВИХІД

thesis:
quotations.txt

thesis_backup:
quotations.txt

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

BASH

$ cp thesis thesis_backup
cp: -r not specified; omitting directory 'thesis'
Вправа

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

Припустімо, що ви створили у поточному каталозі простий текстовий файл, який містить список статистичних тестів, які вам знадобляться для аналізу ваших даних, і назвали його statstics.txt

Після створення і збереження цього файлу ви зрозуміли, що неправильно написали назву файлу! Ви хочете виправити помилку. Яку з наведених нижче команд ви можете використати для цього?

  1. cp statstics.txt statistics.txt
  2. mv statstics.txt statistics.txt
  3. mv statstics.txt .
  4. cp statstics.txt .
  1. Ні. Хоча це створить файл з правильною назвою, неправильно названий файл все одно існуватиме у каталозі, і його потрібно буде видалити.
  2. Так, це спрацює для перейменування файлу.
  3. Ні, крапка (.) вказує, куди перемістити файл, але не надає нового імені файлу; файли з однаковими іменами не можуть бути створені.
  4. Ні, крапка (.) вказує, куди скопіювати файл, але не надає нового імені файлу; файли з однаковими іменами не можуть бути створені.
Вправа

Переміщення та копіювання

Що виводить остання команда ls у наведеній нижче послідовності?

BASH

$ pwd

ВИХІД

/Users/jamie/data

BASH

$ ls

ВИХІД

proteins.dat

BASH

$ mkdir recombined
$ mv proteins.dat recombined/
$ cp recombined/proteins.dat ../proteins-saved.dat
$ ls
  1. proteins-saved.dat recombined
  2. recombined
  3. proteins.dat recombined
  4. proteins-saved.dat

Ми розпочинаємо роботу в каталозі /Users/jamie/data і створюємо нову папку з назвою recombined. Другий рядок переміщує (mv) файл proteins.dat до нового каталогу (recombined). Третій рядок робить копію файлу, який ми щойно перемістили. Складність полягає у тому, куди саме було скопійовано цей файл. Нагадаємо, що .. означає “піднятися на рівень вище”, тому скопійований файл тепер знаходиться у /Users/jamie. Зверніть увагу, що .. інтерпретується відносно поточного робочого каталогу, а не відносно розташування файлу, який копіюється. Отже, єдине, що буде показано за допомогою команди ls (у каталозі /Users/jamie/data) - це каталог recombined.

  1. Ні, див. пояснення вище. Каталог proteins-saved.dat розташовано у каталозі /Users/jamie
  2. Так
  3. Ні, див. пояснення вище. Файл proteins.dat знаходиться в каталозі /Users/jamie/data/recombined
  4. Ні, див. пояснення вище. Файл proteins-saved.dat знаходиться в каталозі /Users/jamie

Видалення файлів і каталогів


Повертаючись до каталогу shell-lesson-data/exercise-data/writing, давайте почистимо цей каталог, видаливши створений нами файл quotes.txt. Для цього ми скористаємося командою Unix rm (скорочення від англ. remove - видаляти):

BASH

$ rm quotes.txt

Ми можемо перевірити видалення файлу за допомогою ls:

BASH

$ ls quotes.txt

ПОМИЛКА

ls: cannot access 'quotes.txt': No such file or directory
Виноска

Видалення - це назавжди

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

Вправа

Безпечне використання rm

Що відбувається, коли ми виконуємо rm -i thesis_backup/quotations.txt? Навіщо нам може бути потрібен цей захист при використанні rm?

ВИХІД

rm: remove regular file 'thesis_backup/quotations.txt'? y

Параметр -i призведе до окремого запиту перед (кожним) вилученням (використовуйте Y для підтвердження вилучення або N, щоб зберегти файл). У командному терміналі Unix немає кошика, тому видалені файли зникнуть назавжди. Використання опції -i дає можливість перевірити, що ми видаляємо лише обрані файли.

Якщо ми спробуємо видалити каталог thesis за допомогою rm thesis, ми отримаємо повідомлення про помилку:

BASH

$ rm thesis

ПОМИЛКА

rm: cannot remove `thesis': Is a directory

Це відбувається тому, що команда rm за замовчуванням працює лише з файлами, а не з каталогами.

Команда rm може видалити каталог і весь його вміст, якщо додати рекурсивний параметр -r, і це станеться без жодних запитів на підтвердження:

BASH

$ rm -r thesis

Оскільки файли, видалені за допомогою терміналу не відновлюються, команду rm -r слід застосовувати з великою обережністю (ви можете додати інтерактивну опцію rm -r -i).

Операції з декількома файлами та каталогами


Час від часу нам знадобиться скопіювати або перемістити кілька файлів одночасно. Для цього треба надати список імен окремих файлів, або вказати шаблон імен за допомогою символів підстановки. Це символи, які можна використовувати для представлення невідомих символів або груп символів під час навігації по файловій системі Unix.

Вправа

Копіювання кількох файлів водночас

Для цієї вправи ви можете випробувати команди у каталозі shell-lesson-data/exercise-data.

Що робить команда cp у наведеному нижче прикладі, коли їй надано декілька імен файлів і назву каталогу?

BASH

$ mkdir backup
$ cp creatures/minotaur.dat creatures/unicorn.dat backup/

Що робить команда cp у наведеному нижче прикладі, коли їй задано три або більше імен файлів?

BASH

$ cd creatures
$ ls -F

ВИХІД

basilisk.dat  minotaur.dat  unicorn.dat

BASH

$ cp minotaur.dat unicorn.dat basilisk.dat

Якщо надано декілька імен файлів та ім’я каталогу (каталог призначення має бути останнім аргументом), команда cp копіює файли до вказаного каталогу.

Якщо надано тільки три імені файлів, то cp видасть помилку, подібну до наведеної нижче, бо останній аргумент повинен бути ім’ям каталогу.

ПОМИЛКА

cp: target 'basilisk.dat' is not a directory

Використання символів підстановки для роботи з кількома файлами одночасно

Виноска

Символи підстановки

Символ * - це символ підстановки (wildcard), який відповідає нулю або більшій кількості будь-яких символів. Розглянемо каталог shell-lesson-data/exercise-data/proteins: *.pdb відповідає ethane.pdb, propane.pdb і кожному файлу, який закінчується на ‘.pdb’. З іншого боку, p*.pdb підходить тільки для файлів pentane.pdb і propane.pdb, оскільки початкова літера ‘p’ лише збігається з назвами файлів, які починаються з літери ‘p’.

Символ ? також є символом підстановки, але він відповідає рівно одному будь-якому символу. Отже, ?ethane.pdb буде відповідати methane.pdb, тоді як *ethane.pdb відповідає як ethane.pdb, так і methane.pdb.

Символи підстановки можна використовувати разом, комбінуючи їх у шаблонах. Наприклад, ???ane.pdb відповідає трьом символам, за якими слідує ane.pdb, що дає cubane.pdb ethane.pdb octane.pdb.

Коли термінал бачить символ підстановки, він розгортає його для створення списку відповідних імен файлів до запуску команди, яку було введено. Як виняток, якщо вираз підстановки не відповідає жодному файлу, Bash передасть вираз як аргумент до команди, якою вона є. Наприклад, введення ls *.pdf у каталозі proteins (який містить лише файли з іменами, що закінчуються на .pdb) призведе до повідомлення про те, що не існує файлу з назвою *.pdf. Втім, зазвичай команди на кшталт wc і ls показують списки імен файлів, які відповідають цим виразам, але не самим символам підстановки. Саме термінал, а не інші програми, виконує розкриття символів підстановки.

Вправа

Отримання переліку імен файлів, що відповідають шаблону

При виконанні в каталозі alkanes, яка з команд ls видасть наступний результат?

ethane.pdb methane.pdb

  1. ls *t*ane.pdb
  2. ls *t?ne.*
  3. ls *t??ne.pdb
  4. ls ethane.*

Відповіддю є 3.

1. показує всі файли, назви яких починаюьться з нуля або більше символів (*), за якими йде літера t, потім нуль або більше символів (*) і далі ane.pdb. Це дасть ethane.pdb methane.pdb octane.pdb pentane.pdb.

2. показує всі файли, назви яких починаються з нуля або більше символів (*), за якими йде літера t, потім один будь-який символ (?), потім ne. і далі нуль або більше символів (*). Це дасть нам octane.pdb і pentane.pdb, але не збігається ні з чим, що закінчується на thane.pdb.

3. виправляє проблеми варіанта 2, вимагаючи два символи (??) між t і ne. Це і є рішення.

4. показує лише файли, що починаються з ethane..

Вправа

Більше про символи підстановки

Саманта має каталог, який містить дані калібрування, набори даних та їх описи:

BASH

.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
│   ├── calibration
│   └── datasets
└── send_to_bob
    ├── all_datasets_created_on_a_23rd
    └── all_november_files

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

BASH

$ cp *dataset* backup/datasets
$ cp ____calibration____ backup/calibration
$ cp 2015-____-____ send_to_bob/all_november_files/
$ cp ____ send_to_bob/all_datasets_created_on_a_23rd/

Допоможіть Саманті, заповнивши пропуски.

Отримана структура каталогів повинна виглядати наступним чином:

BASH

.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
│   ├── calibration
│   │   ├── 2015-10-23-calibration.txt
│   │   ├── 2015-10-26-calibration.txt
│   │   └── 2015-11-23-calibration.txt
│   └── datasets
│       ├── 2015-10-23-dataset1.txt
│       ├── 2015-10-23-dataset2.txt
│       ├── 2015-10-23-dataset_overview.txt
│       ├── 2015-10-26-dataset1.txt
│       ├── 2015-10-26-dataset2.txt
│       ├── 2015-10-26-dataset_overview.txt
│       ├── 2015-11-23-dataset1.txt
│       ├── 2015-11-23-dataset2.txt
│       └── 2015-11-23-dataset_overview.txt
└── send_to_bob
    ├── all_datasets_created_on_a_23rd
    │   ├── 2015-10-23-dataset1.txt
    │   ├── 2015-10-23-dataset2.txt
    │   ├── 2015-10-23-dataset_overview.txt
    │   ├── 2015-11-23-dataset1.txt
    │   ├── 2015-11-23-dataset2.txt
    │   └── 2015-11-23-dataset_overview.txt
    └── all_november_files
        ├── 2015-11-23-calibration.txt
        ├── 2015-11-23-dataset1.txt
        ├── 2015-11-23-dataset2.txt
        └── 2015-11-23-dataset_overview.txt

BASH

$ cp *calibration.txt backup/calibration
$ cp 2015-11-* send_to_bob/all_november_files/
$ cp *-23-dataset* send_to_bob/all_datasets_created_on_a_23rd/
Вправа

Упорядкування каталогів і файлів

Джеймі працює над проєктом і бачить, що її файли не дуже добре впорядковані:

BASH

$ ls -F

ВИХІД

analyzed/  fructose.dat    raw/   sucrose.dat

Файли fructose.dat та sucrose.dat містять результати її аналізу. Яку (які) команду (команди), розглянуту (розглянуті) у цьому уроці, їй потрібно виконати, щоб наведені нижче команди вивели результати наведені нижче?

BASH

$ ls -F

ВИХІД

analyzed/   raw/

BASH

$ ls analyzed

ВИХІД

fructose.dat sucrose.dat

BASH

mv *.dat analyzed

Джеймі потрібно перемістити файли fructose.dat та sucrose.dat до каталогу analyzed. Термінал розгорне шаблон *.dat до переліку усіх файлів .dat у поточному каталозі. Команда mv перемістить ці файли .dat до каталогу ‘analyzed’.

Вправа

Відтворення структури каталогів

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

Припустимо, що попередній експеримент знаходиться у каталозі з назвою 2016-05-18, який містить каталог data, який аналогічно містить каталоги raw і processed у яких містяться файли даних. Мета полягає у копіюванні структури 2016-05-18 до каталогу 2016-05-20 таким чином, щоб ваша фінальна структура виглядала наступним чином:

ВИХІД

2016-05-20/
└── data
   ├── processed
   └── raw

Який з наведених нижче наборів команд досягне цієї мети? Що зроблять інші команди?

BASH

$ mkdir 2016-05-20
$ mkdir 2016-05-20/data
$ mkdir 2016-05-20/data/processed
$ mkdir 2016-05-20/data/raw

BASH

$ mkdir 2016-05-20
$ cd 2016-05-20
$ mkdir data
$ cd data
$ mkdir raw processed

BASH

$ mkdir 2016-05-20/data/raw
$ mkdir 2016-05-20/data/processed

BASH

$ mkdir -p 2016-05-20/data/raw
$ mkdir -p 2016-05-20/data/processed

BASH

$ mkdir 2016-05-20
$ cd 2016-05-20
$ mkdir data
$ mkdir raw processed

Перші два набори команд досягають цієї мети. Перший набір використовує відносні шляхи для створення каталогу верхнього рівня перед створенням підкаталогів.

Третій набір команд призведе до помилки, оскільки поведінка mkdir за замовчуванням не створює підкаталог в каталозі, що не існує: спочатку мають бути створені каталоги проміжних рівнів.

Четвертий набір команд теж досягає цієї мети. Пам’ятайте, що опція -p, після якої вказується шлях до одного або декількох каталогів, змусить mkdir створити будь-які проміжні підкаталоги за потреби.

Останній набір команд створить каталоги ‘raw’ і ‘processed’ на тому ж рівні, що і каталог ‘data’.

Ключові моменти
  • cp [old] [new] копіює файл.
  • mkdir [path] створює новий каталог.
  • mv [old] [new] переміщує (перейменовує) файл або каталог.
  • rm [path] вилучає (видаляє) файл.
  • * відповідає нулю або більшій кількості символів в імені файлу, тому *.txt відповідає всім файлам, імена яких закінчуються на .txt.
  • ? відповідає будь-якому одному символу у назві файлу, тому ?.txt відповідає a.txt, але не any.txt.
  • Використання клавіші Control можна описати різними способами, зокрема Ctrl-X, Control-X та ^X.
  • В терміналі немає кошика для сміття: як тільки щось видалено - його неможливо відновити.
  • Більшість файлів мають назву на кшталт “щось.розширення”. Розширення не є обов’язковим і нічого не гарантує, але зазвичай використовується для позначення типу даних у файлі.
  • Залежно від типу вашої роботи вам може знадобитися потужніший ніж Nano текстовий редактор.

Content from Канали та фільтри


Останнє оновлення 2025-09-04 | Редагувати цю сторінку

Огляд

Питання

  • Як я можу комбінувати команди, що вже існують, щоб робити нові речі?
  • Як відобразити лише частину виведених даних?

Цілі

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

Тепер, після ознайомлення з основними командами, ми можемо нарешті розглянути найпотужнішу функцію терміналу: здатність комбінувати наявні програми різними способами. Ми почнемо з каталогу shell-lesson-data/exercise-data/proteins, який містить шість файлів, що описують деякі прості органічні молекули. Розширення .pdb вказує на те, що ці файли мають формат Protein Data Bank - простий текстовий формат, який визначає тип і положення кожного атома в молекулі.

BASH

$ ls

ВИХІД

cubane.pdb    methane.pdb    pentane.pdb
ethane.pdb    octane.pdb     propane.pdb

Запустимо наприклад цю команду:

BASH

$ wc cubane.pdb

ВИХІД

20 156 1158 cubane.pdb

wc - команда для підрахунку слів (англ. ‘word count’): вона рахує кількість рядків, слів і символів у файлах (повертаючи значення в такому порядку зліва направо).

Якщо ми виконаємо команду wc *.pdb, то символ * у *.pdb відповідає будь-якій кількості символів (включаючи пустий рядок), тож термінал перетворить *.pdb на перелік усіх файлів з розширенням .pdb у поточному каталозі:

BASH

$ wc *.pdb

ВИХІД

  20  156  1158  cubane.pdb
  12  84   622   ethane.pdb
   9  57   422   methane.pdb
  30  246  1828  octane.pdb
  21  165  1226  pentane.pdb
  15  111  825   propane.pdb
 107  819  6081  total

Зверніть увагу, що wc *.pdb в останньому рядку свого виводу також показує загальну кількість усіх рядків у перелічених файлах.

Якщо ми виконаємо wc -l замість просто wc, то виводитиметься лише кількість рядків у файлах:

BASH

$ wc -l .pdb

ВИХІД

  20  cubane.pdb
  12  ethane.pdb
   9  methane.pdb
  30  octane.pdb
  21  pentane.pdb
  15  propane.pdb
 107  total

Параметри -m та -w з командою wc дозволяють показувати тільки кількість символів або тільки кількість слів у файлах.

Виноска

Чому нічого не відбувається?

Що станеться, коли команді, яка має обробляти файл, не надати його назву? Наприклад, що буде, якщо ми наберемо:

BASH

$ wc -l

але не будемо вводити *.pdb (або щось інше) після цієї команди? Оскільки команда не отримала жодних назв файлів, wc вважає, що треба обробляти введені дані з командного рядка, тому вона просто очікує, поки ми надамо їй якісь дані інтерактивно. Ззовні, однак, це виглядає так, ніби команда нічого не робить.

Якщо ви припустилися такої помилки, ви можете вийти з цього стану, утримуючи клавішу control (Ctrl), та один раз натиснувши клавішу C: Ctrl+C. Потім відпустіть обидві клавіші.

Перехоплення виводу з команд


Який з цих файлів містить найменшу кількість рядків? Це легко визначити, коли файлів лише шість, але що робити, якщо їх 6000? Наш перший крок до пошуку рішення - це запуск наступної команди:

BASH

$ wc -l *.pdb > lengths.txt

Символ ‘більше ніж’, тобто >, вказує терміналу перенаправити вивід команди до файлу замість виведення його на екран. Ця команда не виводить дані на екран, оскільки увесь вивід wc записується до файлу lengths.txt. Якщо файлу не існувало до виконання команди, його буде створено. Якщо файл вже існує, він буде непомітно перезаписаний, що може призвести до втрати даних. Таким чином, перенаправлення команд вимагає обережності.

Команда ls lengths.txt підтверджує, що файл існує:

BASH

$ ls lengths.txt

ВИХІД

lengths.txt

Тепер ми можемо вивести вміст файлу lengths.txt на екран за допомогою команди cat lengths.txt. Назва команди cat походить від слова ‘concatenate’, тобто об’єднувати, і вона виводить вміст файлів один за одним. У цьому випадку є лише один файл, тому cat просто виводить нам його вміст:

BASH

$ cat lengths.txt

ВИХІД

  20  cubane.pdb
  12  ethane.pdb
   9  methane.pdb
  30  octane.pdb
  21  pentane.pdb
  15  propane.pdb
 107  total
Виноска

Виведення сторінки за сторінкою

У цьому уроці, для зручності та послідовності ми й надалі використовуватимемо команду cat, але її недолік полягає в тому, що вона завжди показує весь файл одразу. Більш корисною на практиці є команда less (наприклад, less lengths.txt). Вона виводить стільки вмісту файлу, скільки вміщується в одному екрані, а потім робить паузу. Ви можете перейти на один екран вперед, натиснувши пробіл, або на один екран назад, натиснувши клавішу b. Щоб вийти з перегляду вмісту файлу, натисніть q.

Фільтрування виводу


Далі ми скористаємося командою sort для сортування вмісту файлу lengths.txt. Але спершу виконаємо вправу, щоб трохи ознайомитися з командою sort:

Вправа

Що робить sort -n?

Файл shell-lesson-data/exercise-data/numbers.txt містить наступні рядки:

10
2
19
22
6

Якщо ми виконаємо команду sort для цього файлу, то отримаємо наступне:

ВИХІД

10
19
2
22
6

Якщо ми виконаємо команду sort -n для того ж файлу, то замість цього ми отримаємо наступне:

ВИХІД

2
6
10
19
22

Поясніть, чому -n має такий ефект.

Опція -n задає числове, а не алфавітно-цифрове сортування.

Ми також використовуватимемо опцію -n, щоб задати числове сортування замість алфавітно-цифрового. Це не змінить файл; натомість відсортований результат буде виведено на екран:

BASH

$ sort -n lengths.txt

ВИХІД

  9  methane.pdb
 12  ethane.pdb
 15  propane.pdb
 20  cubane.pdb
 21  pentane.pdb
 30  octane.pdb
107  total

Ми можемо записати відсортований список рядків в інший тимчасовий файл з назвою sorted-lengths.txt, додавши > sorted-lengths.txt після команди, так само як ми використовували > lengths.txt, щоб записати вивід wc у lengths.txt. Потім можна скористатися командою head, щоб отримати перші кілька рядків у sorted-lengths.txt:

BASH

$ sort -n lengths.txt > sorted-lengths.txt
$ head -n 1 sorted-lengths.txt

ВИХІД

  9 methane.pdb

Використання -n 1 з head вказує команді, що нам потрібен лише перший рядок файлу; -n 20 поверне перші 20 тощо. Оскільки файл sorted-lengths.txt містить довжини наших файлів, впорядковані від найменшої до найбільшої, виведенням head має бути файл з найменшою кількістю рядків.

Виноска

Перенаправлення до того ж самого файлу

Намагатися перенаправити вивід команди, яка працює з файлом, у той самий файл — дуже погана ідея. Наприклад:

BASH

$ sort -n lengths.txt > lengths.txt

Виконання таких дій може надати вам некоректні результати та/або видалити вміст файлу lengths.txt.

Вправа

Що означає >>?

Ми вже розглядали оператор >, але ще існує схожий оператор >>, який працює трохи інакше. Ми дізнаємося про відмінності між цими двома операторами, надрукувавши кілька рядків. Для виведення рядків ми можемо скористатися командою echo, наприклад:

BASH

$ echo The echo command prints text

ВИХІД

The echo command prints text

Тепер протестуйте наведені нижче команди, щоб виявити різницю між цими двома операторами:

BASH

$ echo hello > testfile01.txt

та:

BASH

$ echo hello >> testfile02.txt

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

У першому прикладі з > рядок ‘hello’ записується до файлу testfile01.txt, але файл перезаписується кожного разу, коли ми запускаємо команду.

З другого прикладу ми бачимо, що оператор >> також записує рядок ‘hello’ у файл (у цьому випадку testfile02.txt), але додає рядок до файлу, якщо останній вже існує (тобто, коли ми запускаємо його вдруге).

Вправа

Додавання даних у кінець файлу

Ми вже знайомі з командою head, яка виводить рядки з початку файлу. Команда tail схожа на неї, але виводить рядки з кінця файлу.

Розглянемо файл shell-lesson-data/exercise-data/animal-counts/animals.csv. Після виконання цих команд оберіть відповідь, яка відповідає вмісту файлу animals-subset.csv:

BASH

$ head -n 3 animals.csv > animals-subset.csv
$ tail -n 2 animals.csv >> animals-subset.csv
  1. Перші три рядки файлу animals.csv
  2. Останні два рядки файлу animals.csv
  3. Перші три рядки та останні два рядки файлу animals.csv
  4. Другий і третій рядки файлу animals.csv

Варіант 3 є правильним. Щоб варіант 1 був правильним, потрібно виконати лише команду head. Щоб варіант 2 був правильним, нам слід виконати лише команду tail. Щоб варіант 4 був коректним, нам слід передати вивід команди head у команду tail -n 2 виконавши head -n 3 animals.csv | tail -n 2 > animals-subset.csv

Передача виводу іншій команді


У нашому прикладі для пошуку файлу з найменшою кількістю рядків, ми використовуємо два проміжні файли lengths.txt та sorted-lengths.txt для зберігання результатів. Такий підхід може збивати з пантелику, оскільки навіть зрозумівши як працюють wc, sort і head, ці проміжні файли ускладнюють відстеження всього процесу. Щоб легше було зрозуміти, можна одночасно виконати sort і head:

BASH

$ sort -n lengths.txt | head -n 1

ВИХІД

  9 methane.pdb

Вертикальна риска | між двома командами називається каналом (pipe). Вона вказує терміналу, що вивід команди ліворуч слід використати як вхідні дані для команди праворуч.

Це усуває необхідність у файлі sorted-lengths.txt.

Поєднання декількох команд


Ніщо не заважає нам з’єднувати канали послідовно. Наприклад, ми можемо надсилати вивід wc безпосередньо до sort, а потім результат — до head. Це усуває необхідність у будь-яких проміжних файлах.

Ми почнемо з використання каналу для надсилання виводу wc до sort:

BASH

$ wc -l *.pdb | sort -n

ВИХІД

   9 methane.pdb
  12 ethane.pdb
  15 propane.pdb
  20 cubane.pdb
  21 pentane.pdb
  30 octane.pdb
 107 total

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

BASH

$ wc -l *.pdb | sort -n | head -n 1

ВИХІД

   9 methane.pdb

Це подібне тому, як в математиці ми розглядаємо складні функції на кшталт log(3x) і кажемо ‘логарифм трьох x*’. У нашому випадку, обчислюється ‘head від sort від підрахунку кількості рядків у файлах *.pdb’.

Перенаправлення та канали, використані в останніх кількох командах, проілюстровані нижче:

Перенаправлення та канали різних команд: "wc -l *.pdb" перенаправить виведення до терміналу. "wc -l *.pdb lengths" спрямує вивід до файлу "lengths". "wc -l *.pdb | sort -n | head -n 1" побудує конвеєр, де вихід команди "wc" передається як вхідні дані до "sort", вихід команди "sort" є входом для команди "head", а результат команди "head" буде спрямовано до терміналу
Вправа

З’єднання команд у конвеєр

У нашому поточному каталозі ми хочемо знайти 3 файли, які мають найменшу кількість рядків. Яка з наведених нижче команд підійде для цього?

  1. wc -l * > sort -n > head -n 3
  2. wc -l * | sort -n | head -n 1-3
  3. wc -l * | head -n 3 | sort -n
  4. wc -l * | sort -n | head -n 3

Варіант 4 є рішенням. Символ каналу | використовується для під’єднання виводу однієї команди до входу іншої. Символ > використовується для перенаправлення стандартного виводу до файлу. Спробуйте це у каталозі shell-lesson-data/exercise-data/proteins!

Інструменти, створені для співробітництва


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

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

Вправа

Розуміння роботи з каналами

Файл з назвою animals.csv (у каталозі shell-lesson-data/exercise-data/animal-counts) містить наступні дані:

2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-06,fox,4
2012-11-07,rabbit,16
2012-11-07,bear,1

Який текст проходить через кожен із каналів та фінальне перенаправлення у конвеєрі нижче? Зауважте, що команда sort -r сортує у зворотному порядку.

BASH

$ cat animals.csv | head -n 5 | tail -n 3 | sort -r > final.txt

Підказка: створюйте конвеєр по одній команді за раз, щоб перевіряти своє розуміння

Команда head виділяє перші 5 рядків з файлу animals.csv. Потім останні 3 рядки виділяються з попередніх 5 за допомогою команди tail. За допомогою команди sort -r ці 3 рядки сортуються у зворотному порядку. І нарешті, результат перенаправляється до файлу final.txt. Вміст цього файлу можна перевірити, виконавши команду cat final.txt. Файл повинен містити наступні рядки:

2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-05,raccoon,7
Вправа

Конструювання каналу

Для файлу animals.csv з попередньої вправи розглянемо наступну команду:

BASH

$ cut -d , -f 2 animals.csv

Команда cut використовується для видалення або ‘вирізання’ певних частин кожного рядка у файлі. Вона очікує, що рядки буде розділено на стовпчики символом Tab. Символ, який використовується таким чином, називається роздільником. У наведеному вище прикладі ми використали опцію -d, щоб вказати кому як роздільник. Ми також використали опцію -f, щоб зазначити, що ми хочемо вилучити друге поле (стовпчик). Це призведе до наступного результату:

ВИХІД

deer
rabbit
raccoon
rabbit
deer
fox
rabbit
bear

Команда uniq відфільтровує сусідні однакові рядки у файлі. Як можна розширити цей конвеєр (за допомогою uniq та інших команд), щоб з’ясувати, назви яких тварин містяться у файлі (без повторень у їхніх назвах)?

BASH

$ cut -d , -f 2 animals.csv | sort | uniq
Вправа

Який з каналів використати?

Файл animals.csv містить 8 рядків даних, відформатованих наступним чином:

ВИХІД

2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
...

Команда uniq має опцію -c, яка підраховує кількість разів, коли рядок зʼявляється у вхідних даних. Припускаючи що ваш поточний каталог має назву shell-lesson-data/exercise-data/animal-counts, яку команду слід використати, щоб створити таблицю у файлі з підрахунком загальної кількості тварин кожного типу?

  1. sort animals.csv | uniq -c
  2. sort -t, -k2,2 animals.csv | uniq -c
  3. cut -d, -f 2 animals.csv | uniq -c
  4. cut -d, -f 2 animals.csv | sort | uniq -c
  5. cut -d, -f 2 animals.csv | sort | uniq -c | wc -l

Варіант 4. Це правильна відповідь. Якщо вам важко зрозуміти, чому, спробуйте виконати команди або фрагменти конвеєру (перед цим переконайтеся, що ви перебуваєте у каталозі shell-lesson-data/exercise-data/animal-counts).

Конвеєр Неллі: перевірка файлів


Неллі обробила свої зразки в аналізаторах і створила 17 файлів в каталозі north-pacific-gyre, описаному раніше. Для швидкої перевірки, вона переходить у каталог shell-lesson-data та набирає:

BASH

$ cd north-pacific-gyre
$ wc -l *.txt

На виході вона отримує 18 рядків, які виглядають наступним чином:

ВИХІД

300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
300 NENE01751B.txt
300 NENE01812A.txt
... ...

Тепер вона набирає наступне:

BASH

$ wc -l *.txt | sort -n | head -n 5

ВИХІД

 240 NENE02018B.txt
 300 NENE01729A.txt
 300 NENE01729B.txt
 300 NENE01736A.txt
 300 NENE01751A.txt

Ого - несподіванка! Один з файлів на 60 рядків коротший за інші. Коли вона повертається до цього файлу та перевіряє його, вона бачить, що зробила цей аналіз о 8:00 ранку в понеділок — хтось, можливо, користувався машиною на вихідних, і вона забула її перезавантажити. Перед тим, як повторно проаналізувати цей зразок, вона перевіряє, чи є файли, що містять забагато даних:

BASH

$ wc -l *.txt | sort -n | tail -n 5

ВИХІД

 300 NENE02040B.txt
 300 NENE02040Z.txt
 300 NENE02043A.txt
 300 NENE02043B.txt
5040 total

Ці цифри мають сенс — але що робить ця ‘Z’ у другому рядку? Всі її зразки мають бути позначені ‘A’ або ‘B’; за попередньою домовленістю її лабораторія використовує ‘Z’ для позначення зразків з недостатньою інформацією. Щоб знайти інші подібні зразки, вона робить наступне:

BASH

$ ls *Z.txt

ВИХІД

NENE01971Z.txt    NENE02040Z.txt

Справді, коли вона перевіряє файл журналу на своєму ноутбуці, то виявляється, що глибина не була записана для жодного з цих зразків. Оскільки отримати цю інформацію іншим способом вже неможливо, їй доведеться виключити ці два файли з аналізу. Вона може видалити їх за допомогою rm, але деякі подальші аналізи даних не вимагатимуть інформації про глибину, тому їй буде потрібно обережно обирати файли за допомогою шаблонів NENE*A.txt NENE*B.txt.

Вправа

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

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

  1. rm ?.txt
  2. rm *.txt
  3. rm * .txt
  4. rm *.*
  1. Це призведе до вилучення файлів .txt з односимвольними назвами

  2. Це правильна відповідь

  3. Термінал розширить шаблон * до переліку усіх файлів у поточному каталозі, таким чином, команда спробує видалити всі знайдені файли та додатковий файл з назвою `.txt’

  4. Термінал розширює *.* до переліку усіх файлів, назви яких містять принаймні одну крапку (.), включно з обробленими файлами (.txt), і вихідними файлами (.dat)

Ключові моменти
  • wc підраховує рядки, слова та символи у своїх вхідних даних.
  • cat виводить вміст своїх вхідних даних.
  • sort сортує вхідні дані.
  • head за замовчуванням (тобто без додаткових аргументів) виводить перші 10 рядків вхідних даних.
  • tail за замовчуванням (тобто без додаткових аргументів) виводить останні 10 рядків вхідних даних.
  • command > [file] перенаправляє вивід команди у файл (перезаписуючи будь-який наявний вміст цього файлу, якщо файл вже існує).
  • command >> [file] додає вивід команди до файлу.
  • [first] | [second] є конвеєром: вихід першої команди використовується як вхідні дані для другої.
  • Найкращий спосіб використання терміналу - це комбінування простих однозадачних програм (фільтрів) за допомогою каналів.

Content from Цикли


Останнє оновлення 2025-08-22 | Редагувати цю сторінку

Огляд

Питання

  • How can I perform the same actions on many different files?

Цілі

  • Написати цикл, який застосовує одну або декілька команд окремо до кожного файлу в наборі файлів.
  • Простежити, яких значень набуває змінна циклу під час виконання циклу.
  • Пояснити різницю між ім’ям змінної та її значенням.
  • Пояснити, чому в іменах файлів не можна використовувати пробіли та деякі розділові знаки.
  • Продемонструвати, як побачити, які команди були виконані останнім часом.
  • Перезапустити нещодавно виконані команди без повторного введення.

Loops are a programming construct which allow us to repeat a command or set of commands for each item in a list. As such they are key to productivity improvements through automation. Similar to wildcards and tab completion, using loops also reduces the amount of typing required (and hence reduces the number of typing mistakes).

Suppose we have several hundred genome data files named basilisk.dat, minotaur.dat, and unicorn.dat. For this example, we’ll use the exercise-data/creatures directory which only has three example files, but the principles can be applied to many many more files at once.

The structure of these files is the same: the common name, classification, and updated date are presented on the first three lines, with DNA sequences on the following lines. Let’s look at the files:

BASH

$ head -n 5 basilisk.dat minotaur.dat unicorn.dat

We would like to print out the classification for each species, which is given on the second line of each file. For each file, we would need to execute the command head -n 2 and pipe this to tail -n 1. We’ll use a loop to solve this problem, but first let’s look at the general form of a loop, using the pseudo-code below:

BASH

# The word "for" indicates the start of a "For-loop" command
for thing in list_of_things 
#The word "do" indicates the start of job execution list
do 
    # Indentation within the loop is not required, but aids legibility
    operation_using/command $thing 
# The word "done" indicates the end of a loop
done  

and we can apply this to our example like this:

BASH

$ for filename in basilisk.dat minotaur.dat unicorn.dat
> do
>     echo $filename
>     head -n 2 $filename | tail -n 1
> done

ВИХІД

basilisk.dat
CLASSIFICATION: basiliscus vulgaris
minotaur.dat
CLASSIFICATION: bos hominus
unicorn.dat
CLASSIFICATION: equus monoceros
Виноска

Follow the Prompt

The shell prompt changes from $ to > and back again as we were typing in our loop. The second prompt, >, is different to remind us that we haven’t finished typing a complete command yet. A semicolon, ;, can be used to separate two commands written on a single line.

When the shell sees the keyword for, it knows to repeat a command (or group of commands) once for each item in a list. Each time the loop runs (called an iteration), an item in the list is assigned in sequence to the variable, and the commands inside the loop are executed, before moving on to the next item in the list. Inside the loop, we call for the variable’s value by putting $ in front of it. The $ tells the shell interpreter to treat the variable as a variable name and substitute its value in its place, rather than treat it as text or an external command.

In this example, the list is three filenames: basilisk.dat, minotaur.dat, and unicorn.dat. Кожного разу, коли цикл повторюється, ми спочатку використовуємо echo для друку значення, яке зараз містить змінна $filename. This is not necessary for the result, but beneficial for us here to have an easier time to follow along. Далі ми виконаємо команду head для файлу, на який зараз посилається $filename. The first time through the loop, $filename is basilisk.dat. The interpreter runs the command head on basilisk.dat and pipes the first two lines to the tail command, which then prints the second line of basilisk.dat. For the second iteration, $filename becomes minotaur.dat. This time, the shell runs head on minotaur.dat and pipes the first two lines to the tail command, which then prints the second line of minotaur.dat. For the third iteration, $filename becomes unicorn.dat, so the shell runs the head command on that file, and tail on the output of that. Since the list was only three items, the shell exits the for loop.

Виноска

Same Symbols, Different Meanings

Here we see > being used as a shell prompt, whereas > is also used to redirect output. Similarly, $ is used as a shell prompt, but, as we saw earlier, it is also used to ask the shell to get the value of a variable.

If the shell prints > or $ then it expects you to type something, and the symbol is a prompt.

If you type > or $ yourself, it is an instruction from you that the shell should redirect output or get the value of a variable.

When using variables it is also possible to put the names into curly braces to clearly delimit the variable name: $filename is equivalent to ${filename}, but is different from ${file}name. You may find this notation in other people’s programs.

We have called the variable in this loop filename in order to make its purpose clearer to human readers. The shell itself doesn’t care what the variable is called; if we wrote this loop as:

BASH

$ for x in basilisk.dat minotaur.dat unicorn.dat
> do
>     head -n 2 $x | tail -n 1
> done

or:

BASH

$ for temperature in basilisk.dat minotaur.dat unicorn.dat
> do
>     head -n 2 $temperature | tail -n 1
> done

it would work exactly the same way. Don’t do this. Programs are only useful if people can understand them, so meaningless names (like x) or misleading names (like temperature) increase the odds that the program won’t do what its readers think it does.

In the above examples, the variables (thing, filename, x and temperature) could have been given any other name, as long as it is meaningful to both the person writing the code and the person reading it.

Note also that loops can be used for other things than filenames, like a list of numbers or a subset of data.

Вправа

Write your own loop

How would you write a loop that echoes all 10 numbers from 0 to 9?

BASH

$ for loop_variable in 0 1 2 3 4 5 6 7 8 9
> do
>     echo $loop_variable
> done

ВИХІД

0
1
2
3
4
5
6
7
8
9
Вправа

Variables in Loops

This exercise refers to the shell-lesson-data/exercise-data/alkanes directory. ls *.pdb gives the following output:

ВИХІД

cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb

What is the output of the following code?

BASH

$ for datafile in *.pdb
> do
>     ls *.pdb
> done

Now, what is the output of the following code?

BASH

$ for datafile in *.pdb
> do
>     ls $datafile
> done

Чому ці два цикли дають різні результати?

Перший блок коду дає однаковий результат на кожній ітерації циклу. Bash expands the wildcard *.pdb within the loop body (as well as before the loop starts) to match all files ending in .pdb and then lists them using ls. Розширений цикл матиме такий вигляд:

BASH

$ for datafile in cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
> do
>     ls cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
> done

ВИХІД

cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb

The second code block lists a different file on each loop iteration. The value of the datafile variable is evaluated using $datafile, and then listed using ls.

ВИХІД

cubane.pdb
ethane.pdb
methane.pdb
octane.pdb
pentane.pdb
propane.pdb
Вправа

Limiting Sets of Files

Що буде виведено у результаті виконання наступного циклу в каталозі shell-lesson-data/exercise-data/alkanes?

BASH

$ for filename in c*
> do
>     ls $filename
> done
  1. Жодної назви файлу не буде виведено.
  2. Будуть перелічені всі файли.
  3. Будуть перелічені лише cubane.pdb, octane.pdb та pentane.pdb.
  4. Буде виведено лише cubane.pdb.

4 - правильна відповідь. * matches zero or more characters, so any file name starting with the letter c, followed by zero or more other characters will be matched.

Вправа

Limiting Sets of Files (continued)

How would the output differ from using this command instead?

BASH

$ for filename in *c*
> do
>     ls $filename
> done
  1. The same files would be listed.
  2. All the files are listed this time.
  3. No files are listed this time.
  4. The files cubane.pdb and octane.pdb will be listed.
  5. Only the file octane.pdb will be listed.

4 - правильна відповідь. * matches zero or more characters, so a file name with zero or more characters before a letter c and zero or more characters after the letter c will be matched.

Вправа

Saving to a File in a Loop - Part One

In the shell-lesson-data/exercise-data/alkanes directory, what is the effect of this loop?

BASH

for alkanes in *.pdb
do
    echo $alkanes
    cat $alkanes > alkanes.pdb
done
  1. Prints cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, pentane.pdb and propane.pdb, and the text from propane.pdb will be saved to a file called alkanes.pdb.
  2. Prints cubane.pdb, ethane.pdb, and methane.pdb, and the text from all three files would be concatenated and saved to a file called alkanes.pdb.
  3. Prints cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, and pentane.pdb, and the text from propane.pdb will be saved to a file called alkanes.pdb.
  4. None of the above.
  1. The text from each file in turn gets written to the alkanes.pdb file. However, the file gets overwritten on each loop iteration, so the final content of alkanes.pdb is the text from the propane.pdb file.
Вправа

Saving to a File in a Loop - Part Two

Also in the shell-lesson-data/exercise-data/alkanes directory, what would be the output of the following loop?

BASH

for datafile in *.pdb
do
    cat $datafile >> all.pdb
done
  1. Весь текст з файлів cubane.pdb, ethane.pdb, methane.pdb, octane.pdb та pentane.pdb буде об’єднано і збережено у файлі з назвою all.pdb.
  2. Текст з файлу ethane.pdb буде збережено до файлу з назвою all.pdb.
  3. Весь текст з файлів cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, pentane.pdb та propane.pdb буде об’єднано та збережено у файл з назвою all.pdb.
  4. Весь текст з файлів cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, pentane.pdb та propane.pdb буде виведено на екран і збережено у файлі з назвою all.pdb.

3 - правильна відповідь. >> appends to a file, rather than overwriting it with the redirected output from a command. Оскільки вивід команди cat було перенаправлено, на екран нічого не буде виведено.

Let’s continue with our example in the shell-lesson-data/exercise-data/creatures directory. Here’s a slightly more complicated loop:

BASH

$ for filename in *.dat
> do
>     echo $filename
>     head -n 100 $filename | tail -n 20
> done

The shell starts by expanding *.dat to create the list of files it will process. The loop body then executes two commands for each of those files. The first command, echo, prints its command-line arguments to standard output. For example:

BASH

$ echo hello there

prints:

ВИХІД

hello there

In this case, since the shell expands $filename to be the name of a file, echo $filename prints the name of the file. Note that we can’t write this as:

BASH

$ for filename in *.dat
> do
>     $filename
>     head -n 100 $filename | tail -n 20
> done

because then the first time through the loop, when $filename expanded to basilisk.dat, the shell would try to run basilisk.dat as a program. Finally, the head and tail combination selects lines 81-100 from whatever file is being processed (assuming the file has at least 100 lines).

Виноска

Spaces in Names

Spaces are used to separate the elements of the list that we are going to loop over. If one of those elements contains a space character, we need to surround it with quotes, and do the same thing to our loop variable. Припустимо, що наші файли даних мають імена:

red dragon.dat
purple unicorn.dat

To loop over these files, we would need to add double quotes like so:

BASH

$ for filename in "red dragon.dat" "purple unicorn.dat"
> do
>     head -n 100 "$filename" | tail -n 20
> done

Простіше уникати використання пробілів (або інших спеціальних символів) у назвах файлів.

The files above don’t exist, so if we run the above code, the head command will be unable to find them; however, the error message returned will show the name of the files it is expecting:

ПОМИЛКА

head: cannot open ‘red dragon.dat' for reading: No such file or directory
head: cannot open ‘purple unicorn.dat' for reading: No such file or directory

Try removing the quotes around $filename in the loop above to see the effect of the quote marks on spaces. Зверніть увагу, що ми отримуємо результат команди циклу для unicorn.dat коли ми запускаємо цей код у каталозі creatures:

ВИХІД

head: cannot open ‘red' for reading: No such file or directory
head: cannot open ‘dragon.dat' for reading: No such file or directory
head: cannot open ‘purple' for reading: No such file or directory
CGGTACCGAA
AAGGGTCGCG
CAAGTGTTCC
...

We would like to modify each of the files in shell-lesson-data/exercise-data/creatures, but also save a version of the original files. Наприклад, ми хочемо скопіювати оригінальні файли до нових файлів з назвами original-basilisk.dat та original-unicorn.dat. We can’t use:

BASH

$ cp *.dat original-*.dat

because that would expand to:

BASH

$ cp basilisk.dat minotaur.dat unicorn.dat original-*.dat

This wouldn’t back up our files, instead we get an error:

ПОМИЛКА

cp: target `original-*.dat' is not a directory

This problem arises when cp receives more than two inputs. When this happens, it expects the last input to be a directory where it can copy all the files it was passed. Since there is no directory named original-*.dat in the creatures directory, we get an error.

Замість цього ми можемо використати цикл:

BASH

$ for filename in *.dat
> do
>     cp $filename original-$filename
> done

This loop runs the cp command once for each filename. The first time, when $filename expands to basilisk.dat, the shell executes:

BASH

cp basilisk.dat original-basilisk.dat

The second time, the command is:

BASH

cp minotaur.dat original-minotaur.dat

The third and last time, the command is:

BASH

cp unicorn.dat original-unicorn.dat

Since the cp command does not normally produce any output, it’s hard to check that the loop is working correctly. However, we learned earlier how to print strings using echo, and we can modify the loop to use echo to print our commands without actually executing them. As such we can check what commands would be run in the unmodified loop.

The following diagram shows what happens when the modified loop is executed and demonstrates how the judicious use of echo is a good debugging technique.

The for loop "for filename in .dat; do echo cp $filename original-$filename;done" will successively assign the names of all ".dat" files in your currentdirectory to the variable "$filename" and then execute the command. With thefiles "basilisk.dat", "minotaur.dat" and "unicorn.dat" in the current directorythe loop will successively call the echo command three times and print threelines: "cp basislisk.dat original-basilisk.dat", then "cp minotaur.datoriginal-minotaur.dat" and finally "cp unicorn.datoriginal-unicorn.dat"

Nelle’s Pipeline: Processing Files


Nelle is now ready to process her data files using goostats.sh — a shell script written by her supervisor. This calculates some statistics from a protein sample file and takes two arguments:

  1. an input file (containing the raw data)
  2. an output file (to store the calculated statistics)

Since she’s still learning how to use the shell, she decides to build up the required commands in stages. Her first step is to make sure that she can select the right input files — remember, these are ones whose names end in ‘A’ or ‘B’, rather than ‘Z’. Переходячи до каталогу north-pacific-gyre, Неллі вводить:

BASH

$ cd
$ cd Desktop/shell-lesson-data/north-pacific-gyre
$ for datafile in NENE*A.txt NENE*B.txt
> do
>     echo $datafile
> done

ВИХІД

NENE01729A.txt
NENE01729B.txt
NENE01736A.txt
...
NENE02043A.txt
NENE02043B.txt

Her next step is to decide what to call the files that the goostats.sh analysis program will create. Prefixing each input file’s name with ‘stats’ seems simple, so she modifies her loop to do that:

BASH

$ for datafile in NENE*A.txt NENE*B.txt
> do
>     echo $datafile stats-$datafile
> done

ВИХІД

NENE01729A.txt stats-NENE01729A.txt
NENE01729B.txt stats-NENE01729B.txt
NENE01736A.txt stats-NENE01736A.txt
...
NENE02043A.txt stats-NENE02043A.txt
NENE02043B.txt stats-NENE02043B.txt

She hasn’t actually run goostats.sh yet, but now she’s sure she can select the right files and generate the right output filenames.

Typing in commands over and over again is becoming tedious, though, and Nelle is worried about making mistakes, so instead of re-entering her loop, she presses . In response, the shell redisplays the whole loop on one line (using semi-colons to separate the pieces):

BASH

$ for datafile in NENE A.txt NENE B.txt; do echo $datafile stats-$datafile; done

Using the , Nelle navigates to the echo command and changes it to bash goostats.sh:

BASH

$ for datafile in NENE*A.txt NENE*B.txt; do bash goostats.sh $datafile stats-$datafile; done

When she presses Enter, the shell runs the modified command. However, nothing appears to happen — there is no output. After a moment, Nelle realizes that since her script doesn’t print anything to the screen any longer, she has no idea whether it is running, much less how quickly. She kills the running command by typing Ctrl+C, uses to repeat the command, and edits it to read:

BASH

$ for datafile in NENE*A.txt NENE*B.txt; do echo $datafile;
bash goostats.sh $datafile stats-$datafile; done
Виноска

Beginning and End

We can move to the beginning of a line in the shell by typing Ctrl+A and to the end using Ctrl+E.

When she runs her program now, it produces one line of output every five seconds or so:

ВИХІД

NENE01729A.txt
NENE01736A.txt
NENE01751A.txt
...

1518 times 5 seconds, divided by 60, tells her that her script will take about two hours to run. As a final check, she opens another terminal window, goes into north-pacific-gyre, and uses cat stats-NENE01729B.txt to examine one of the output files. It looks good, so she decides to get some coffee and catch up on her reading.

Виноска

Those Who Know History Can Choose to Repeat It

Another way to repeat previous work is to use the history command to get a list of the last few hundred commands that have been executed, and then to use !123 (where ‘123’ is replaced by the command number) to repeat one of those commands. Наприклад, якщо Неллі набере наступне:

BASH

$ history | tail -n 5

ВИХІД

456  for datafile in NENE*A.txt NENE*B.txt; do   echo $datafile stats-$datafile; done
457  for datafile in NENE*A.txt NENE*B.txt; do echo $datafile stats-$datafile; done
458  for datafile in NENE*A.txt NENE*B.txt; do bash goostats.sh $datafile stats-$datafile; done
459  for datafile in NENE*A.txt NENE*B.txt; do echo $datafile; bash goostats.sh $datafile
stats-$datafile; done
460  history | tail -n 5

then she can re-run goostats.sh on the files simply by typing !459.

Виноска

Other History Commands

There are a number of other shortcut commands for getting at the history.

  • Ctrl+R enters a history search mode ‘reverse-i-search’ and finds the most recent command in your history that matches the text you enter next. Press Ctrl+R one or more additional times to search for earlier matches. You can then use the left and right arrow keys to choose that line and edit it then hit Return to run the command.
  • !! повертає безпосередньо попередню команду (ви можете знайти це більш зручним, ніж використання )
  • !$ повертає останнє слово останньої команди. That’s useful more often than you might expect: after bash goostats.sh NENE01729B.txt stats-NENE01729B.txt, you can type less !$ to look at the file stats-NENE01729B.txt, which is quicker than doing and editing the command-line.
Вправа

Doing a Dry Run

A loop is a way to do many things at once — or to make many mistakes at once if it does the wrong thing. One way to check what a loop would do is to echo the commands it would run instead of actually running them.

Suppose we want to preview the commands the following loop will execute without actually running those commands:

BASH

$ for datafile in *.pdb
> do
>     cat $datafile >> all.pdb
> done

What is the difference between the two loops below, and which one would we want to run?

BASH

# Варіант 1
$ for datafile in *.pdb
> do
>     echo cat $datafile >> all.pdb
> done

BASH

# Варіант 2
$ for datafile in *.pdb
> do
>     echo "cat $datafile >> all.pdb"
> done

The second version is the one we want to run. This prints to screen everything enclosed in the quote marks, expanding the loop variable name because we have prefixed it with a dollar sign. It also does not modify nor create the file all.pdb, as the >> is treated literally as part of a string rather than as a redirection instruction.

The first version appends the output from the command echo cat $datafile to the file, all.pdb. This file will just contain the list; cat cubane.pdb, cat ethane.pdb, cat methane.pdb etc.

Try both versions for yourself to see the output! Be sure to open the all.pdb file to view its contents.

Вправа

Nested Loops

Suppose we want to set up a directory structure to organize some experiments measuring reaction rate constants with different compounds and different temperatures. Яким буде результат виконання наступного коду:

BASH

$ for species in cubane ethane methane
> do
>     for temperature in 25 30 37 40
>     do
>         mkdir $species-$temperature
>     done
> done

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

Try running the code for yourself to see which directories are created!

Ключові моменти
  • Цикл for повторює команди один раз для кожного елемента списку.
  • Every for loop needs a variable to refer to the thing it is currently operating on.
  • Use $name to expand a variable (i.e., get its value). Також можна використовувати ${name}.
  • Do not use spaces, quotes, or wildcard characters such as ‘*’ or ‘?’ in filenames, as it complicates variable expansion.
  • Give files consistent names that are easy to match with wildcard patterns to make it easy to select them for looping.
  • Use the up-arrow key to scroll up through previous commands to edit and repeat them.
  • Використовуйте Ctrl+R для пошуку попередньо введених команд.
  • Use history to display recent commands, and ![number] to repeat a command by number.

Content from Shell Scripts


Останнє оновлення 2025-08-28 | Редагувати цю сторінку

Огляд

Питання

  • Як я можу зберігати та повторно використовувати команди?

Цілі

  • Write a shell script that runs a command or series of commands for a fixed set of files.
  • Run a shell script from the command line.
  • Write a shell script that operates on a set of files defined by the user on the command line.
  • Create pipelines that include shell scripts you, and others, have written.

We are finally ready to see what makes the shell such a powerful programming environment. We are going to take the commands we repeat frequently and save them in files so that we can re-run all those operations again later by typing a single command. For historical reasons, a bunch of commands saved in a file is usually called a shell script, but make no mistake — these are actually small programs.

Not only will writing shell scripts make your work faster, but also you won’t have to retype the same commands over and over again. It will also make it more accurate (fewer chances for typos) and more reproducible. If you come back to your work later (or if someone else finds your work and wants to build on it), you will be able to reproduce the same results simply by running your script, rather than having to remember or retype a long list of commands.

Let’s start by going back to alkanes/ and creating a new file, middle.sh which will become our shell script:

BASH

$ cd alkanes
$ nano middle.sh

The command nano middle.sh opens the file middle.sh within the text editor ‘nano’ (which runs within the shell). If the file does not exist, it will be created. We can use the text editor to directly edit the file by inserting the following line:

head -n 15 octane.pdb | tail -n 5

This is a variation on the pipe we constructed earlier, which selects lines 11-15 of the file octane.pdb. Remember, we are not running it as a command just yet; we are only incorporating the commands in a file.

Then we save the file (Ctrl-O in nano) and exit the text editor (Ctrl-X in nano). Check that the directory alkanes now contains a file called middle.sh.

Once we have saved the file, we can ask the shell to execute the commands it contains. Our shell is called bash, so we run the following command:

BASH

$ bash middle.sh

ВИХІД

ATOM      9  H           1      -4.502   0.681   0.785  1.00  0.00
ATOM     10  H           1      -5.254  -0.243  -0.537  1.00  0.00
ATOM     11  H           1      -4.357   1.252  -0.895  1.00  0.00
ATOM     12  H           1      -3.009  -0.741  -1.467  1.00  0.00
ATOM     13  H           1      -3.172  -1.337   0.206  1.00  0.00

Sure enough, our script’s output is exactly what we would get if we ran that pipeline directly.

Виноска

Text vs. Whatever

We usually call programs like Microsoft Word or LibreOffice Writer “text editors”, but we need to be a bit more careful when it comes to programming. By default, Microsoft Word uses .docx files to store not only text, but also formatting information about fonts, headings, and so on. This extra information isn’t stored as characters and doesn’t mean anything to tools like head, which expects input files to contain nothing but the letters, digits, and punctuation on a standard computer keyboard. When editing programs, therefore, you must either use a plain text editor or be careful to save files as plain text.

What if we want to select lines from an arbitrary file? We could edit middle.sh each time to change the filename, but that would probably take longer than typing the command out again in the shell and executing it with a new file name. Instead, let’s edit middle.sh and make it more versatile:

BASH

$ nano middle.sh

Now, within “nano”, replace the text octane.pdb with the special variable called $1:

head -n 15 "$1" | tail -n 5

Inside a shell script, $1 means ‘the first filename (or other argument) on the command line’. We can now run our script like this:

BASH

$ bash middle.sh octane.pdb

ВИХІД

ATOM      9  H           1      -4.502   0.681   0.785  1.00  0.00
ATOM     10  H           1      -5.254  -0.243  -0.537  1.00  0.00
ATOM     11  H           1      -4.357   1.252  -0.895  1.00  0.00
ATOM     12  H           1      -3.009  -0.741  -1.467  1.00  0.00
ATOM     13  H           1      -3.172  -1.337   0.206  1.00  0.00

or on a different file like this:

BASH

$ bash middle.sh pentane.pdb

ВИХІД

ATOM      9  H           1       1.324   0.350  -1.332  1.00  0.00
ATOM     10  H           1       1.271   1.378   0.122  1.00  0.00
ATOM     11  H           1      -0.074  -0.384   1.288  1.00  0.00
ATOM     12  H           1      -0.048  -1.362  -0.205  1.00  0.00
ATOM     13  H           1      -1.183   0.500  -1.412  1.00  0.00
Виноска

Double-Quotes Around Arguments

For the same reason that we put the loop variable inside double-quotes, in case the filename happens to contain any spaces, we surround $1 with double-quotes.

Currently, we need to edit middle.sh each time we want to adjust the range of lines that is returned. Let’s fix that by configuring our script to instead use three command-line arguments. After the first command-line argument ($1), each additional argument that we provide will be accessible via the special variables $1, $2, $3, which refer to the first, second, third command-line arguments, respectively.

Knowing this, we can use additional arguments to define the range of lines to be passed to head and tail respectively:

BASH

$ nano middle.sh
head -n "$2" "$1" | tail -n "$3"

We can now run:

BASH

$ bash middle.sh pentane.pdb 15 5

ВИХІД

ATOM      9  H           1       1.324   0.350  -1.332  1.00  0.00
ATOM     10  H           1       1.271   1.378   0.122  1.00  0.00
ATOM     11  H           1      -0.074  -0.384   1.288  1.00  0.00
ATOM     12  H           1      -0.048  -1.362  -0.205  1.00  0.00
ATOM     13  H           1      -1.183   0.500  -1.412  1.00  0.00

By changing the arguments to our command, we can change our script’s behaviour:

BASH

$ bash middle.sh pentane.pdb 20 5

ВИХІД

ATOM     14  H           1      -1.259   1.420   0.112  1.00  0.00
ATOM     15  H           1      -2.608  -0.407   1.130  1.00  0.00
ATOM     16  H           1      -2.540  -1.303  -0.404  1.00  0.00
ATOM     17  H           1      -3.393   0.254  -0.321  1.00  0.00
TER      18              1

This works, but it may take the next person who reads middle.sh a moment to figure out what it does. We can improve our script by adding some comments at the top:

BASH

$ nano middle.sh
# Виділення рядків з середини файлу.
# Використання: bash middle.sh filename end_line num_lines
head -n "$2" "$1" | tail -n "$3"

A comment starts with a # character and runs to the end of the line. The computer ignores comments, but they’re invaluable for helping people (including your future self) understand and use scripts. Єдине застереження полягає у тому, що кожного разу, коли ви змінюєте скрипт, ви повинні перевіряти, що коментар все ще правильний. Пояснення, яке спрямовує читача в неправильному напрямку, гірше, ніж його відсутність.

What if we want to process many files in a single pipeline? For example, if we want to sort our .pdb files by length, we would type:

BASH

$ wc -l *.pdb | sort -n

because wc -l lists the number of lines in the files (recall that wc stands for ‘word count’, adding the -l option means ‘count lines’ instead) and sort -n sorts things numerically. We could put this in a file, but then it would only ever sort a list of .pdb files in the current directory. If we want to be able to get a sorted list of other kinds of files, we need a way to get all those names into the script. We can’t use $1, $2, and so on because we don’t know how many files there are. Instead, we use the special variable $@, which means, ‘All of the command-line arguments to the shell script’. We also should put $@ inside double-quotes to handle the case of arguments containing spaces ("$@" is special syntax and is equivalent to "$1" "$2" …).

Here’s an example:

BASH

$ nano sorted.sh
# Сортування файлів за їх розміром.
# Використання: bash sorted.sh one_or_more_filenames
wc -l "$@" | sort -n

BASH

$ bash sorted.sh *.pdb ../creatures/*.dat

ВИХІД

9 methane.pdb
12 ethane.pdb
15 propane.pdb
20 cubane.pdb
21 pentane.pdb
30 octane.pdb
163 ../creatures/basilisk.dat
163 ../creatures/minotaur.dat
163 ../creatures/unicorn.dat
596 total
Вправа

List Unique Species

Лія має кілька сотень файлів даних, кожен з яких відформатований наступним чином:

2013-11-05,deer,5
2013-11-05,rabbit,22
2013-11-05,raccoon,7
2013-11-06,rabbit,19
2013-11-06,deer,2
2013-11-06,fox,1
2013-11-07,rabbit,18
2013-11-07,bear,1

An example of this type of file is given in shell-lesson-data/exercise-data/animal-counts/animals.csv.

We can use the command cut -d , -f 2 animals.csv | sort | uniq to produce the unique species in animals.csv. In order to avoid having to type out this series of commands every time, a scientist may choose to write a shell script instead.

Write a shell script called species.sh that takes any number of filenames as command-line arguments and uses a variation of the above command to print a list of the unique species appearing in each of those files separately.

BASH

# Script to find unique species in csv files where species is the second data field
# This script accepts any number of file names as command line arguments

# Loop over all files
for file in $@
do
    echo "Unique species in $file:"
    # Extract species names
    cut -d , -f 2 $file | sort | uniq
done

Suppose we have just run a series of commands that did something useful — for example, creating a graph we’d like to use in a paper. We’d like to be able to re-create the graph later if we need to, so we want to save the commands in a file. Instead of typing them in again (and potentially getting them wrong) we can do this:

BASH

$ history | tail -n 5 > redo-figure-3.sh

The file redo-figure-3.sh now contains:

297 bash goostats.sh NENE01729B.txt stats-NENE01729B.txt
298 bash goodiff.sh stats-NENE01729B.txt /data/validated/01729.txt > 01729-differences.txt
299 cut -d ',' -f 2-3 01729-differences.txt > 01729-time-series.txt
300 ygraph --format scatter --color bw --borders none 01729-time-series.txt figure-3.png
301 history | tail -n 5 > redo-figure-3.sh

After a moment’s work in an editor to remove the serial numbers on the commands, and to remove the final line where we called the history command, we have a completely accurate record of how we created that figure.

Вправа

Why Record Commands in the History Before Running Them?

Якщо виконати команду:

BASH

$ history | tail -n 5 > recent.sh

останньою командою у файлі є сама команда history, тобто, термінал додав history до журналу команд перед тим, як фактично її виконав. In fact, the shell always adds commands to the log before running them. Why do you think it does this?

If a command causes something to crash or hang, it might be useful to know what that command was, in order to investigate the problem. Were the command only be recorded after running it, we would not have a record of the last command run in the event of a crash.

In practice, most people develop shell scripts by running commands at the shell prompt a few times to make sure they’re doing the right thing, then saving them in a file for re-use. This style of work allows people to recycle what they discover about their data and their workflow with one call to history and a bit of editing to clean up the output and save it as a shell script.

Nelle’s Pipeline: Creating a Script


Nelle’s supervisor insisted that all her analytics must be reproducible. The easiest way to capture all the steps is in a script.

First we return to Nelle’s project directory:

BASH

$ cd ../../north-pacific-gyre/

She creates a file using nano

BASH

$ nano do-stats.sh

…which contains the following:

BASH

# Calculate stats for data files.
for datafile in "$@"
do
    echo $datafile
    bash goostats.sh $datafile stats-$datafile
done

She saves this in a file called do-stats.sh so that she can now re-do the first stage of her analysis by typing:

BASH

$ bash do-stats.sh NENE*A.txt NENE*B.txt

She can also do this:

BASH

$ bash do-stats.sh NENE*A.txt NENE*B.txt | wc -l

so that the output is just the number of files processed rather than the names of the files that were processed.

One thing to note about Nelle’s script is that it lets the person running it decide what files to process. She could have written it as:

BASH

# Calculate stats for Site A and Site B data files.
for datafile in NENE*A.txt NENE*B.txt
do
    echo $datafile
    bash goostats.sh $datafile stats-$datafile
done

The advantage is that this always selects the right files: she doesn’t have to remember to exclude the ‘Z’ files. The disadvantage is that it always selects just those files — she can’t run it on all files (including the ‘Z’ files), or on the ‘G’ or ‘H’ files her colleagues in Antarctica are producing, without editing the script. If she wanted to be more adventurous, she could modify her script to check for command-line arguments, and use NENE*A.txt NENE*B.txt if none were provided. Of course, this introduces another tradeoff between flexibility and complexity.

Вправа

Variables in Shell Scripts

Уявіть, що у каталозі alkanes у вас є скрипт з назвою script.sh, який містить наступні команди:

BASH

head -n $2 $1
tail -n $3 $1

Перебуваючи у каталозі alkanes, ви вводите наступну команду:

BASH

$ bash script.sh '*.pdb' 1 1

Які з наведених нижче результатів ви очікуєте побачити?

  1. Усі рядки між першим та останнім рядками кожного файлу, що закінчується на .pdb у каталозі alkanes
  2. Перший та останній рядок кожного файлу, що закінчується на .pdb у каталозі alkanes
  3. Перший та останній рядок кожного файлу в каталозі alkanes
  4. Помилку через лапки навколо *.pdb

The correct answer is 2.

The special variables $1, $2 and $3 represent the command line arguments given to the script, such that the commands run are:

BASH

$ head -n 1 cubane.pdb ethane.pdb octane.pdb pentane.pdb propane.pdb
$ tail -n 1 cubane.pdb ethane.pdb octane.pdb pentane.pdb propane.pdb

The shell does not expand '*.pdb' because it is enclosed by quote marks. Таким чином, першим аргументом скрипту є '*.pdb', який буде розгорнуто у скрипті за допомогою head і tail.

Вправа

Find the Longest File With a Given Extension

Напишіть сценарій терміналу з назвою longest.sh, який отримує в якості аргументів ім’я каталогу і розширення імені файлу як аргументи, і виводить назву файлу з найбільшою кількістю рядків у цьому каталозі з цим розширенням. For example:

BASH

$ bash longest.sh shell-lesson-data/exercise-data/alkanes pdb

виведе назву файлу .pdb у каталозі shell-lesson-data/exercise-data/proteins, який має найбільшу кількість рядків.

Feel free to test your script on another directory e.g.

BASH

$ bash longest.sh shell-lesson-data/exercise-data/writing txt

BASH

# Shell script which takes two arguments:
#    1. a directory name
#    2. a file extension
# and prints the name of the file in that directory
# with the most lines which matches the file extension.

wc -l $1/*.$2 | sort -n | tail -n 2 | head -n 1

The first part of the pipeline, wc -l $1/*.$2 | sort -n, counts the lines in each file and sorts them numerically (largest last). When there’s more than one file, wc also outputs a final summary line, giving the total number of lines across all files. Ми використовуємо tail -n 2 | head -n 1, щоб відкинути цей останній рядок.

With wc -l $1/*.$2 | sort -n | tail -n 1 we’ll see the final summary line: we can build our pipeline up in pieces to be sure we understand the output.

Вправа

Script Reading Comprehension

For this question, consider the shell-lesson-data/exercise-data/alkanes directory once again. This contains a number of .pdb files in addition to any other files you may have created. Explain what each of the following three scripts would do when run as bash script1.sh *.pdb, bash script2.sh *.pdb, and bash script3.sh *.pdb respectively.

BASH

# Script 1
echo *.*

BASH

# Script 2
for filename in $1 $2 $3
do
    cat $filename
done

BASH

# Script 3
echo $@.pdb

In each case, the shell expands the wildcard in *.pdb before passing the resulting list of file names as arguments to the script.

Script 1 would print out a list of all files containing a dot in their name. The arguments passed to the script are not actually used anywhere in the script.

Script 2 would print the contents of the first 3 files with a .pdb file extension. $1, $2, and $3 refer to the first, second, and third argument respectively.

Script 3 would print all the arguments to the script (i.e. all the .pdb files), followed by .pdb. $@ refers to all the arguments given to a shell script.

ВИХІД

cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb.pdb
Вправа

Debugging Scripts

Suppose you have saved the following script in a file called do-errors.sh in Nelle’s north-pacific-gyre directory:

BASH

# Calculate stats for data files.
for datafile in "$@"
do
    echo $datfile
    bash goostats.sh $datafile stats-$datafile
done

When you run it from the north-pacific-gyre directory:

BASH

$ bash do-errors.sh NENE*A.txt NENE*B.txt

the output is blank. To figure out why, re-run the script using the -x option:

BASH

$ bash -x do-errors.sh NENE*A.txt NENE*B.txt

What is the output showing you? Which line is responsible for the error?

The -x option causes bash to run in debug mode. This prints out each command as it is run, which will help you to locate errors. In this example, we can see that echo isn’t printing anything. We have made a typo in the loop variable name, and the variable datfile doesn’t exist, hence returning an empty string.

Ключові моменти
  • Save commands in files (usually called shell scripts) for re-use.
  • bash [filename] runs the commands saved in a file.
  • $@ refers to all of a shell script’s command-line arguments.
  • $1, $2, etc., refer to the first command-line argument, the second command-line argument, etc.
  • Place variables in quotes if the values might have spaces in them.
  • Letting users decide what files to process is more flexible and more consistent with built-in Unix commands.

Content from Finding Things


Останнє оновлення 2025-08-07 | Редагувати цю сторінку

Огляд

Питання

  • How can I find files?
  • How can I find things in files?

Цілі

  • Use grep to select lines from text files that match simple patterns.
  • Use find to find files and directories whose names match simple patterns.
  • Use the output of one command as the command-line argument(s) to another command.
  • Explain what is meant by ‘text’ and ‘binary’ files, and why many common tools don’t handle the latter well.

In the same way that many of us now use ‘Google’ as a verb meaning ‘to find’, Unix programmers often use the word ‘grep’. ‘grep’ is a contraction of ‘global/regular expression/print’, a common sequence of operations in early Unix text editors. It is also the name of a very useful command-line program.

grep finds and prints lines in files that match a pattern. For our examples, we will use a file that contains three haiku taken from a 1998 competition in Salon magazine (Credit to authors Bill Torcaso, Howard Korder, and Margaret Segall, respectively. See Haiku Error Messsages archived Page 1 and Page 2 .). For this set of examples, we’re going to be working in the writing subdirectory:

BASH

$ cd
$ cd Desktop/shell-lesson-data/exercise-data/writing
$ cat haiku.txt

ВИХІД

The Tao that is seen
Is not the true Tao, until
You bring fresh toner.

With searching comes loss
and the presence of absence:
"My Thesis" not found.

Yesterday it worked
Today it is not working
Software is like that.

Let’s find lines that contain the word ‘not’:

BASH

$ grep not haiku.txt

ВИХІД

Is not the true Tao, until
"My Thesis" not found
Today it is not working

Here, not is the pattern we’re searching for. The grep command searches through the file, looking for matches to the pattern specified. To use it type grep, then the pattern we’re searching for and finally the name of the file (or files) we’re searching in.

The output is the three lines in the file that contain the letters ‘not’.

By default, grep searches for a pattern in a case-sensitive way. In addition, the search pattern we have selected does not have to form a complete word, as we will see in the next example.

Let’s search for the pattern: ‘The’.

BASH

$ grep The haiku.txt

ВИХІД

The Tao that is seen
"My Thesis" not found.

This time, two lines that include the letters ‘The’ are outputted, one of which contained our search pattern within a larger word, ‘Thesis’.

To restrict matches to lines containing the word ‘The’ on its own, we can give grep the -w option. This will limit matches to word boundaries.

Later in this lesson, we will also see how we can change the search behavior of grep with respect to its case sensitivity.

BASH

$ grep -w The haiku.txt

ВИХІД

The Tao that is seen

Note that a ‘word boundary’ includes the start and end of a line, so not just letters surrounded by spaces. Sometimes we don’t want to search for a single word, but a phrase. We can also do this with grep by putting the phrase in quotes.

BASH

$ grep -w "is not" haiku.txt

ВИХІД

Today it is not working

We’ve now seen that you don’t have to have quotes around single words, but it is useful to use quotes when searching for multiple words. It also helps to make it easier to distinguish between the search term or phrase and the file being searched. We will use quotes in the remaining examples.

Another useful option is -n, which numbers the lines that match:

BASH

$ grep -n "it" haiku.txt

ВИХІД

5:With searching comes loss
9:Yesterday it worked
10:Today it is not working

Here, we can see that lines 5, 9, and 10 contain the letters ‘it’.

We can combine options (i.e. flags) as we do with other Unix commands. For example, let’s find the lines that contain the word ‘the’. We can combine the option -w to find the lines that contain the word ‘the’ and -n to number the lines that match:

BASH

$ grep -n -w "the" haiku.txt

ВИХІД

2:Is not the true Tao, until
6:and the presence of absence:

Now we want to use the option -i to make our search case-insensitive:

BASH

$ grep -n -w -i "the" haiku.txt

ВИХІД

1:The Tao that is seen
2:Is not the true Tao, until
6:and the presence of absence:

Now, we want to use the option -v to invert our search, i.e., we want to output the lines that do not contain the word ‘the’.

BASH

$ grep -n -w -v "the" haiku.txt

ВИХІД

1:The Tao that is seen
3:You bring fresh toner.
4:
5:With searching comes loss
7:"My Thesis" not found.
8:
9:Yesterday it worked
10:Today it is not working
11:Software is like that.

If we use the -r (recursive) option, grep can search for a pattern recursively through a set of files in subdirectories.

Let’s search recursively for Yesterday in the shell-lesson-data/exercise-data/writing directory:

BASH

$ grep -r Yesterday .

ВИХІД

./LittleWomen.txt:"Yesterday, when Aunt was asleep and I was trying to be as still as a
./LittleWomen.txt:Yesterday at dinner, when an Austrian officer stared at us and then
./LittleWomen.txt:Yesterday was a quiet day spent in teaching, sewing, and writing in my
./haiku.txt:Yesterday it worked

grep has lots of other options. To find out what they are, we can type:

BASH

$ grep --help

ВИХІД

Usage: grep [OPTION]... PATTERN [FILE]...
Search for PATTERN in each FILE or standard input.
PATTERN is, by default, a basic regular expression (BRE).
Example: grep -i 'hello world' menu.h main.c

Regexp selection and interpretation:
  -E, --extended-regexp     PATTERN is an extended regular expression (ERE)
  -F, --fixed-strings       PATTERN is a set of newline-separated fixed strings
  -G, --basic-regexp        PATTERN is a basic regular expression (BRE)
  -P, --perl-regexp         PATTERN is a Perl regular expression
  -e, --regexp=PATTERN      use PATTERN for matching
  -f, --file=FILE           obtain PATTERN from FILE
  -i, --ignore-case         ignore case distinctions
  -w, --word-regexp         force PATTERN to match only whole words
  -x, --line-regexp         force PATTERN to match only whole lines
  -z, --null-data           a data line ends in 0 byte, not newline

Miscellaneous:
...        ...        ...
Вправа

Using grep

Which command would result in the following output:

ВИХІД

and the presence of absence:
  1. grep "of" haiku.txt
  2. grep -E "of" haiku.txt
  3. grep -w "of" haiku.txt
  4. grep -i "of" haiku.txt

The correct answer is 3, because the -w option looks only for whole-word matches. The other options will also match ‘of’ when part of another word.

Виноска

Wildcards

grep‘s real power doesn’t come from its options, though; it comes from the fact that patterns can include wildcards. (The technical name for these is regular expressions, which is what the ’re’ in ‘grep’ stands for.) Regular expressions are both complex and powerful; if you want to do complex searches, please look at the lesson on our website. As a taster, we can find lines that have an ‘o’ in the second position like this:

BASH

$ grep -E "^.o" haiku.txt

ВИХІД

You bring fresh toner.
Today it is not working
Software is like that.

We use the -E option and put the pattern in quotes to prevent the shell from trying to interpret it. (If the pattern contained a *, for example, the shell would try to expand it before running grep.) The ^ in the pattern anchors the match to the start of the line. The . matches a single character (just like ? in the shell), while the o matches an actual ‘o’.

Вправа

Tracking a Species

Leah has several hundred data files saved in one directory, each of which is formatted like this:

2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-06,fox,4
2012-11-07,rabbit,16
2012-11-07,bear,1

She wants to write a shell script that takes a species as the first command-line argument and a directory as the second argument. The script should return one file called <species>.txt containing a list of dates and the number of that species seen on each date. For example using the data shown above, rabbit.txt would contain:

2012-11-05,22
2012-11-06,19
2012-11-07,16

Below, each line contains an individual command, or pipe. Arrange their sequence in one command in order to achieve Leah’s goal:

BASH

cut -d : -f 2
>
|
grep -w $1 -r $2
|
$1.txt
cut -d , -f 1,3

Hint: use man grep to look for how to grep text recursively in a directory and man cut to select more than one field in a line.

An example of such a file is provided in shell-lesson-data/exercise-data/animal-counts/animals.csv

grep -w $1 -r $2 | cut -d : -f 2 | cut -d , -f 1,3 > $1.txt

Actually, you can swap the order of the two cut commands and it still works. At the command line, try changing the order of the cut commands, and have a look at the output from each step to see why this is the case.

You would call the script above like this:

BASH

$ bash count-species.sh bear .
Вправа

Little Women

You and your friend, having just finished reading Little Women by Louisa May Alcott, are in an argument. Of the four sisters in the book, Jo, Meg, Beth, and Amy, your friend thinks that Jo was the most mentioned. You, however, are certain it was Amy. Luckily, you have a file LittleWomen.txt containing the full text of the novel (shell-lesson-data/exercise-data/writing/LittleWomen.txt). Using a for loop, how would you tabulate the number of times each of the four sisters is mentioned?

Hint: one solution might employ the commands grep and wc and a |, while another might utilize grep options. There is often more than one way to solve a programming task, so a particular solution is usually chosen based on a combination of yielding the correct result, elegance, readability, and speed.

for sis in Jo Meg Beth Amy
do
    echo $sis:
    grep -ow $sis LittleWomen.txt | wc -l
done

Alternative, slightly inferior solution:

for sis in Jo Meg Beth Amy
do
    echo $sis:
    grep -ocw $sis LittleWomen.txt
done

This solution is inferior because grep -c only reports the number of lines matched. The total number of matches reported by this method will be lower if there is more than one match per line.

Perceptive observers may have noticed that character names sometimes appear in all-uppercase in chapter titles (e.g. ‘MEG GOES TO VANITY FAIR’). If you wanted to count these as well, you could add the -i option for case-insensitivity (though in this case, it doesn’t affect the answer to which sister is mentioned most frequently).

While grep finds lines in files, the find command finds files themselves. Again, it has a lot of options; to show how the simplest ones work, we’ll use the shell-lesson-data/exercise-data directory tree shown below.

ВИХІД

.
├── animal-counts/
│   └── animals.csv
├── creatures/
│   ├── basilisk.dat
│   ├── minotaur.dat
│   └── unicorn.dat
├── numbers.txt
├── alkanes/
│   ├── cubane.pdb
│   ├── ethane.pdb
│   ├── methane.pdb
│   ├── octane.pdb
│   ├── pentane.pdb
│   └── propane.pdb
└── writing/
    ├── haiku.txt
    └── LittleWomen.txt

The exercise-data directory contains one file, numbers.txt and four directories: animal-counts, creatures, alkanes and writing containing various files.

For our first command, let’s run find . (remember to run this command from the shell-lesson-data/exercise-data folder).

BASH

$ find .

ВИХІД

.
./writing
./writing/LittleWomen.txt
./writing/haiku.txt
./creatures
./creatures/basilisk.dat
./creatures/unicorn.dat
./creatures/minotaur.dat
./animal-counts
./animal-counts/animals.csv
./numbers.txt
./alkanes
./alkanes/ethane.pdb
./alkanes/propane.pdb
./alkanes/octane.pdb
./alkanes/pentane.pdb
./alkanes/methane.pdb
./alkanes/cubane.pdb

As always, the . on its own means the current working directory, which is where we want our search to start. find’s output is the names of every file and directory under the current working directory. This can seem useless at first but find has many options to filter the output and in this lesson we will discover some of them.

The first option in our list is -type d that means ‘things that are directories’. Sure enough, find’s output is the names of the five directories (including .):

BASH

$ find . -type d

ВИХІД

.
./writing
./creatures
./animal-counts
./alkanes

Notice that the objects find finds are not listed in any particular order. If we change -type d to -type f, we get a listing of all the files instead:

BASH

$ find . -type f

ВИХІД

./writing/LittleWomen.txt
./writing/haiku.txt
./creatures/basilisk.dat
./creatures/unicorn.dat
./creatures/minotaur.dat
./animal-counts/animals.csv
./numbers.txt
./alkanes/ethane.pdb
./alkanes/propane.pdb
./alkanes/octane.pdb
./alkanes/pentane.pdb
./alkanes/methane.pdb
./alkanes/cubane.pdb

Now let’s try matching by name:

BASH

$ find . -name *.txt

ВИХІД

./numbers.txt

We expected it to find all the text files, but it only prints out ./numbers.txt. The problem is that the shell expands wildcard characters like * before commands run. Since *.txt in the current directory expands to ./numbers.txt, the command we actually ran was:

BASH

$ find . -name numbers.txt

find did what we asked; we just asked for the wrong thing.

To get what we want, let’s do what we did with grep: put *.txt in quotes to prevent the shell from expanding the * wildcard. This way, find actually gets the pattern *.txt, not the expanded filename numbers.txt:

BASH

$ find . -name "*.txt"

ВИХІД

./writing/LittleWomen.txt
./writing/haiku.txt
./numbers.txt
Виноска

Listing vs. Finding

ls and find can be made to do similar things given the right options, but under normal circumstances, ls lists everything it can, while find searches for things with certain properties and shows them.

As we said earlier, the command line’s power lies in combining tools. We’ve seen how to do that with pipes; let’s look at another technique. As we just saw, find . -name "*.txt" gives us a list of all text files in or below the current directory. How can we combine that with wc -l to count the lines in all those files?

The simplest way is to put the find command inside $():

BASH

$ wc -l $(find . -name "*.txt")

ВИХІД

  21022 ./writing/LittleWomen.txt
     11 ./writing/haiku.txt
      5 ./numbers.txt
  21038 total

When the shell executes this command, the first thing it does is run whatever is inside the $(). It then replaces the $() expression with that command’s output. Since the output of find is the three filenames ./writing/LittleWomen.txt, ./writing/haiku.txt, and ./numbers.txt, the shell constructs the command:

BASH

$ wc -l ./writing/LittleWomen.txt ./writing/haiku.txt ./numbers.txt

which is what we wanted. This expansion is exactly what the shell does when it expands wildcards like * and ?, but lets us use any command we want as our own ‘wildcard’.

It’s very common to use find and grep together. The first finds files that match a pattern; the second looks for lines inside those files that match another pattern. Here, for example, we can find txt files that contain the word “searching” by looking for the string ‘searching’ in all the .txt files in the current directory:

BASH

$ grep "searching" $(find . -name "*.txt")

ВИХІД

./writing/LittleWomen.txt:sitting on the top step, affected to be searching for her book, but was
./writing/haiku.txt:With searching comes loss
Вправа

Matching and Subtracting

The -v option to grep inverts pattern matching, so that only lines which do not match the pattern are printed. Given that, which of the following commands will find all .dat files in creatures except unicorn.dat? Once you have thought about your answer, you can test the commands in the shell-lesson-data/exercise-data directory.

  1. find creatures -name "*.dat" | grep -v unicorn
  2. find creatures -name *.dat | grep -v unicorn
  3. grep -v "unicorn" $(find creatures -name "*.dat")
  4. None of the above.

Option 1 is correct. Putting the match expression in quotes prevents the shell expanding it, so it gets passed to the find command.

Option 2 also works in this instance because the shell tries to expand *.dat but there are no *.dat files in the current directory, so the wildcard expression gets passed to find. We first encountered this in episode 3.

Option 3 is incorrect because it searches the contents of the files for lines which do not match ‘unicorn’, rather than searching the file names.

Виноска

Binary Files

We have focused exclusively on finding patterns in text files. What if your data is stored as images, in databases, or in some other format?

A handful of tools extend grep to handle a few non text formats. But a more generalizable approach is to convert the data to text, or extract the text-like elements from the data. On the one hand, it makes simple things easy to do. On the other hand, complex things are usually impossible. For example, it’s easy enough to write a program that will extract X and Y dimensions from image files for grep to play with, but how would you write something to find values in a spreadsheet whose cells contained formulas?

A last option is to recognize that the shell and text processing have their limits, and to use another programming language. When the time comes to do this, don’t be too hard on the shell. Many modern programming languages have borrowed a lot of ideas from it, and imitation is also the sincerest form of praise.

The Unix shell is older than most of the people who use it. It has survived so long because it is one of the most productive programming environments ever created — maybe even the most productive. Its syntax may be cryptic, but people who have mastered it can experiment with different commands interactively, then use what they have learned to automate their work. Graphical user interfaces may be easier to use at first, but once learned, the productivity in the shell is unbeatable. And as Alfred North Whitehead wrote in 1911, ‘Civilization advances by extending the number of important operations which we can perform without thinking about them.’

Вправа

find Pipeline Reading Comprehension

Write a short explanatory comment for the following shell script:

BASH

wc -l $(find . -name "*.dat") | sort -n
  1. Find all files with a .dat extension recursively from the current directory

  2. Count the number of lines each of these files contains

  3. Sort the output from step 2. numerically

Ключові моменти
  • find finds files with specific properties that match patterns.
  • grep selects lines in files that match patterns.
  • --help is an option supported by many bash commands, and programs that can be run from within Bash, to display more information on how to use these commands or programs.
  • man [command] displays the manual page for a given command.
  • $([command]) inserts a command’s output in place.