Як я відрізняю вихід двох команд?


165

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

diff `ls old` `ls new`

Але я бачу, чому це не працює; diffпередається великий довгий список файлів у командному рядку, а не два потоки, як я сподівався. Як передати два виходи безпосередньо для розходження?


Відповіді:


246

Заміна команди підміняє `…`висновок команди в командному рядку, тому diffсписок файлів в обох каталогах бачить як аргументи. Вам потрібно diffпобачити два імені файлів у його командному рядку, а вміст цих файлів - списки каталогів. Ось що робить заміна процесу .

diff <(ls old) <(ls new)

Аргументи для diffвиглядатимуть /dev/fd/3і /dev/fd/4: вони дескриптори , відповідні двох труб , створених Баш. Коли diffвідкриються ці файли, вони будуть підключені до сторони читання кожної труби. Сторона запису кожної труби з'єднана з lsкомандою.


49
echo <(echo) <(echo)ніколи не думав, що це може бути таким цікавим: D
Сила Водолія

3
Заміна процесу підтримується не всіми оболонками , але перенаправлення труб - це акуратне рішення .
Irfan434

1
Просто кажучи вже про те , що розбір Ls не рекомендується unix.stackexchange.com/questions/128985/why-not-parse-ls
Кату

@Katu Проблема lsполягає в тому, що він обробляє назви файлів. Розбір результатів неміцний (він не працює з "дивними" іменами файлів). Якщо порівнювати два списки каталогів, це нормально, поки вихід однозначний. Для довільних імен файлів для цього потрібна така опція, як --quoting-style=escape.
Жиль

1
@will <(…)створює трубу. Здається, що муль не працює з трубами, тому не можна використовувати <(…). У zsh ви можете замінити <(…)на, =(…)і він буде працювати, оскільки =(…)розміщує проміжні виходи у тимчасовий файл. У bash, я не думаю, що немає зручного синтаксису, вам доведеться самостійно керувати тимчасовими файлами.
Жиль

3

Для zsh, використання =(command)автоматично створює тимчасовий файл і замінює =(command)шлях до самого файлу. При команді Substitution $(command)замінюється висновком команди.

Отже, є три варіанти:

  1. Заміна команд: $(...)
  2. Заміна процесу: <(...)
  3. Заміна процесів із ароматом zsh: =(...)

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

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

Для "Більше порівняння" зауважте, що ви повинні використовувати bcompдля вищезазначеного (замість bcompare), оскільки bcompзапускає порівняння і чекає його завершення. Якщо ви використовуєте bcompare, це запускає порівняння і негайно виходить із-за чого тимчасові файли, створені для зберігання виводу команд, зникають.

Детальніше читайте тут: http://zsh.sourceforge.net/Intro/intro_7.html

Також зауважте це:

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

і наступне, що полягає в різниці між двома типами заміщення Процесу, підтримуваним zsh (тобто №2 та №3):

Якщо ви читаєте чоловічу сторінку zsh, ви можете помітити, що <(...) - це ще одна форма заміни процесу, схожа на = (...). Існує важлива різниця між ними. У випадку <(...) оболонка створює названу трубку (FIFO) замість файлу. Це краще, оскільки воно не заповнює файлову систему; але це працює не у всіх випадках. Насправді, якби ми замінили = (...) на <(...) у наведених вище прикладах, усі вони перестали б працювати, за винятком fgrep -f <(...). Ви не можете редагувати трубу або відкривати її як поштову папку; fgrep, однак, не має проблем з читанням списку слів із труби. Вам може бути цікаво, чому смуга diff <(foo) не працює, оскільки foo | різні роботи; це тому, що diff створює тимчасовий файл, якщо він помічає, що одним з його аргументів є -, а потім копіює його стандартний вхід у тимчасовий файл.

Довідка: https://unix.stackexchange.com/questions/393349/difference-bet between-subshells-and-process-substitution


2
$(...)це не підміна процесу, це підміна команд . <(...)- процес заміщення. Ось чому цитований уривок взагалі не згадується $(...).
муру

2

Рибна шкаралупа

У рибній оболонці вам доведеться трубу в psub . Ось приклад порівняння heroku та dokku конфігурації з Beyond Compare :

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)

1
Іншим графічним інструментом meldрозробки є те, що є відкритим кодом та доступний у сховищах Ubuntu та EPEL. meldmerge.org
phiphi

0

Я часто використовую техніку, описану в прийнятій відповіді:

diff <(ls old) <(ls new)

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

Я вважаю, що 99% часу я випробовую відповідні команди перед запуском розл. Отже, команди, які я хочу відрізняти, є саме в моїй історії ... чому б не використовувати їх?

Я використовую вбудований bash Fix Command (fc) для виконання двох останніх команд:

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A

Прапорцями fc є:

-n : Немає числа. Він пригнічує номери команд при переліку.

-l : Лістинг: Команди перераховані на стандартний вихід.

-1 -1відносяться до початкового і кінцевого полаганію в історії, в цьому випадку його від останньої команди до останньої команди , яка дає тільки останню команду.

Нарешті, ми завершуємо це, $()щоб виконати команду в нижній частині.

Очевидно, це трохи болісно, ​​щоб ми могли створити псевдонім:

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

Або ми можемо створити функцію:

dl() {
    if [[ -z "$1" ]]; then
        first="1"
    else
        first="$1"
    fi
    if [[ -z "$2" ]]; then
        last="2"
    else
        last="$2"
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.