Я замінив Fish на Nushell як оболонку входу в macOS. Fish уже був зручним. Він мав хороші доповнення, прив’язки клавіш у стилі vi, Starship і скорочення, якими я користуюся щодня. Nu мав зберегти це відчуття й дати мені зручніший спосіб працювати з виводом команд.
Перехід виправдав себе, бо модель даних Nu раз у раз стає в пригоді у звичайних командах і невеликих скриптах. Тепер оболонкою входу в моєму обліковому записі macOS є Nu, а Fish досі встановлений і навіть надає кілька доповнень, які Nu не може згенерувати сам.
Fish встановив високу планку
Fish уже давав мені потрібні можливості інтерактивної оболонки. Його автопідказки, підсвічування синтаксису й доповнення (opens in a new tab) (відкриється в новій вкладці) працювали добре, а моя конфігурація додавала Starship, історію Atuin, Zoxide, Mise і власні прив’язки клавіш. Згенеровані інтеграції я кешував, щоб оболонка запускалася швидко.
У конфігурації Fish списки також проходили через eza: ls показував
піктограми й застосовував корисний порядок сортування, а ll додавав стан Git до
детального подання. Ці псевдоніми давали зручний для читання вивід, але для
подальшої фільтрації я мав розбирати текст або викликати іншу команду, яка
повертала машинозчитуваний формат.
Репозиторій із моєю конфігурацією Nushell існує з 12 серпня 2025 року. Він
залишався експериментом до 3 серпня 2026 року, коли я змінив оболонку входу для
облікового запису й закомітив більший набір змін із назвою make Nushell viable as a daily shell. Наступні кілька днів я закривав прогалини в доповненнях,
налаштовував кеші запуску й поведінку рядка запрошення та вносив невеликі
виправлення сумісності.
Рядки, з якими можна працювати далі
Команди Nu передають типізовані значення через конвеєри (opens in a new tab) (відкриється в новій вкладці). Серед цих значень можуть бути записи, списки, таблиці, дати, тривалості й розміри файлів. Зовнішні команди й далі повертають текст або байти, тому звичні конвеєри Unix продовжують працювати. Найбільше користі я отримую, коли команда Nu вже повертає дані з відомою структурою.
ls повертає таблицю. Я можу відфільтрувати каталоги, відсортувати їх за
колонкою modified і вибрати потрібні колонки без розбору текстового виводу:
ls
| where type == dir
| sort-by modified --reverse
| select name modifiedУ конфігурації Nu я навмисно залишив вбудовані ls і open. ls залишається
командою Nu за замовчуванням. Я можу запускати eza напряму, а ll використовує
його, коли мені потрібні піктограми й стан Git. Я ще вирішую, чи вистачить мені
стандартного ls для щоденної роботи. Коли хочу продовжити роботу з результатом,
використовую його структуровані рядки. open package.json читає JSON як запис, а
решта конвеєра працює з полями:
open package.json
| get scripts
| transpose name command
| sort-by nameУ Nu є вбудовані конвертери для JSON, TOML, YAML, CSV та інших форматів. Кожен
конвертер очікує структуру значення, сумісну з цільовим форматом. У форматах,
якими я користуюся, перехід від from json до to toml більше схожий на вибір
типу виводу, ніж на складання ще одного текстового конвеєра.
Таблиця з CLI стає конфігурацією Codex
Я вже пробував Nushell як щоденну оболонку. Приклад із codex features list
допоміг мені оцінити модель даних Nu й залишитися з Nushell. Codex виводить
список можливостей як вирівняний текст. Для такого виводу я використовую detect columns:
^codex features list
| detect columns --guess --no-headers
| rename name stage enabled
| update enabled { into bool }
| where stage in ['under development' stable] and enabled == false
| reduce --fold {} {|feature, config|
$config | upsert $feature.name true
}
| to toml
| pbcopydetect columns перетворює текст на рядки, rename дає колонкам зрозумілі
назви, а update перетворює enabled із тексту на логічні значення. where
залишає вимкнені можливості з двома потрібними статусами. reduce формує один
запис, ключами якого стають назви можливостей, а to toml створює рядки, які я
можу вставити під [features] у ~/.codex/config.toml. pbcopy копіює
отриманий рядок у буфер обміну macOS.
detect columns вгадує структуру за розташуванням (opens in a new tab) (відкриється в новій вкладці),
тому я використовую його як адаптер для стабільного текстового виводу. Якщо CLI
підтримує JSON, я вибираю його. Тоді решта конвеєра працює з тими самими записами
й фільтрами та не залежить від пробілів між колонками.
Паралельні оновлення без каші у виводі
Через update-tools я однією командою оновлюю Homebrew, Mise, Claude, Codex і
глобальні Skills:
export def update-tools [] {
let jobs = [
{
name: Homebrew
commands: [
{|| brew upgrade -y }
{|| brew cleanup }
]
}
{
name: Mise
commands: [
{|| mise upgrade }
]
}
{
name: Claude
commands: [
{|| claude update }
]
}
{
name: Codex
commands: [
{|| codex update }
]
}
{
name: Skills
commands: [
{|| skills update -g -y }
]
}
]
$jobs | par-each --threads 5 { |job|
let results = (
$job.commands
| each { |command|
with-env {
CLICOLOR_FORCE: "1"
FORCE_COLOR: "1"
HOMEBREW_COLOR: "1"
} {
do $command o+e>| complete
}
}
)
let output = (
$results
| get stdout
| str join
| str trim
)
let succeeded = (
$results
| all { |result| $result.exit_code == 0 }
)
let heading = if $succeeded {
$"(ansi green_bold)✓ ($job.name)(ansi reset)"
} else {
$"(ansi red_bold)✗ ($job.name)(ansi reset)"
}
print $"\n($heading)\n($output)"
} | ignore
}Зовнішній список складається із записів. У кожному є назва для виводу й одне
або кілька замикань із командами. par-each --threads 5 запускає п’ять записів
із завданнями паралельно, а внутрішній each зберігає послідовність команд у межах
одного завдання. Homebrew запускає очищення після оновлення. Mise, Claude, Codex
і Skills не чекають на цю пару.
o+e>| complete об’єднує потоки виводу команди, запускає замикання й повертає
структурований результат із полями stdout та exit_code. Функція з’єднує
вивід кожного завдання, перевіряє всі коди завершення й друкує для нього окремий
зелений або червоний блок. Блоки можуть з’являтися в порядку завершення, оскільки
без окремої вказівки par-each не зберігає порядок вхідних даних.
Fish уміє запускати фонові завдання через & і чекати на них. У Nu весь облік
лишається частиною тієї самої функції: завдання зберігаються як записи, команди
як замикання, а результати мають поля. Замість довгого ланцюжка
mise upgrade && claude update && codex update я запускаю незалежні частини
паралельно й отримую окремий
читабельний блок від кожного з п’яти інструментів.
Я зберіг решту налаштувань термінала
Я продовжую користуватися тим самим ~/.config/starship.toml. Fish завантажував
згенерований вивід starship init fish, а Nu завантажує кешований
starship init nu. Мій промпт із $all, кольори, стан Git і тривалість
виконання команд не змінилися. Atuin, Zoxide, Mise і Carapace я теж зберіг
завдяки їхнім інтеграціям із Nu.
Доповнення потребували більше роботи. Я використовую вбудовані доповнення Nu для Git і Claude, Carapace як загальний резервний варіант і невеликі окремі адаптери для прогалин. Codex і Herdr у моїх версіях можуть генерувати доповнення Fish, але не мають власних доповнень для Nu, тому моя система доповнень передає ці файли через Fish. Через це я не видалив Fish і після зміни оболонки входу.
Файли .nu я пишу в Neovim. Увімкнення
додаткового модуля Nushell у LazyVim (opens in a new tab) (відкриється в новій вкладці)
через :LazyExtras налаштувало мовний сервер Nushell і встановило парсер nu
для Treesitter. LSP добре допомагає писати функції й знаходити помилки в
замиканнях. Оскільки Neovim у мене вже був налаштований, для цього вистачило
одного перемикача.
Для окремих завдань я й далі використовую jq, yq, rg і fd
Nushell замінив Fish як мою щоденну оболонку. Я зберіг спеціалізовані інструменти
командного рядка, яким уже довіряв. Я використовую jq для JSON і yq для YAML,
коли їхні мови запитів найзручніші для завдання або коли команда має працювати
поза Nu. Через rg я шукаю у вмісті файлів, а через fd знаходжу файли. bat
досі дає мені зручний для читання вивід файлів.
Я вибираю Nu, коли сама оболонка знає структуру даних: у результатах ls і
open, під час роботи з датами чи розмірами файлів або у виводі CLI, який я
можу розібрати на стабільні колонки. Nu також підходить для невеликих скриптів,
де треба фільтрувати записи, паралельно виконувати роботу, перевіряти коди
завершення й серіалізувати результат.
Nushell не сумісний із POSIX, а
посібник із використання його як типової оболонки (opens in a new tab) (відкриється в новій вкладці)
попереджає, що деякі програми розраховують на POSIX-сумісну оболонку входу.
Підтримка доповнень для зовнішніх команд різниться. detect columns і далі
вгадує структуру, а для кількох інструментів мені довелося зробити кеші й
адаптери. Якщо скрипт очікує Fish, я можу запустити його однією командою.
Я можу переглядати, фільтрувати й серіалізувати списки каталогів або таблиці з
виводу CLI, не зводячи їх до тексту, а update-tools керує паралельними
завданнями. Цього поки що достатньо, щоб залишити Nu моєю оболонкою входу.
Подивимося, як піде далі.
Джерела
- Nushell: конвеєри (opens in a new tab) (відкриється в новій вкладці)
- Nushell: типи даних (opens in a new tab) (відкриється в новій вкладці)
- Nushell: завантаження даних (opens in a new tab) (відкриється в новій вкладці)
-
Nushell:
ls(opens in a new tab) (відкриється в новій вкладці) -
Nushell:
detect columns(opens in a new tab) (відкриється в новій вкладці) -
Nushell:
par-each(opens in a new tab) (відкриється в новій вкладці) -
Nushell:
complete(opens in a new tab) (відкриється в новій вкладці) -
Nushell:
to toml(opens in a new tab) (відкриється в новій вкладці) - Посібник Fish (opens in a new tab) (відкриється в новій вкладці)
- LazyVim: додатковий модуль Nushell (opens in a new tab) (відкриється в новій вкладці)