Різна різниця у Bash


110

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

Я бачу, що comm, diff, cmp всі дозволяють передавати або два файли, або файл та стандартний вхід - я думаю, це добре, якщо я не хочу виводити два файли ... але все одно це відстійно.

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


1
що ти насправді хочеш зробити?

Ви можете використовувати маніпуляції з підрядками та вбудовані тестові операції зі змінами IFS для порівняння, але вам потрібно знати, чи хочете ви порівнювати символи за символом, словом за словом, рядком за рядком, ігнорувати пробіл ...
technosaurus

Відповіді:


198

Використовуючи diffабо comщо завгодно:

diff  <(echo "$string1" ) <(echo "$string2")

Greg's Bash FAQ: Процес заміни

або з названою трубою

mkfifo ./p
diff - p <<< "$string1" & echo "$string2" > p

Питання та відповіді Грега Баша: Робота з названими трубами

Названа труба також відома як FIFO.

Сама -по собі призначена для стандартного введення.

<<< - це рядок "тут".

&це як, ;але ставить його на другий план


5
+1 за правильну відповідь. +1 для великого пояснення символів. Крім того, Грега Bash FAQ переїхав: mywiki.wooledge.org Посилання на зазначені сторінки в даний час в mywiki.wooledge.org/ProcessSubstitution і mywiki.wooledge.org/BashFAQ/085
timemachine3030

Дякую! а також це покаже динамічні дескриптори файлівFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Водолій Сила

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

Це, здається, працює, якщо є кілька рядків у $ string1 та $ string2, і diff виводить рядки, додані чи віднімані. Що робити, якщо рядок - це один рядок, а рядок, і між двома рядками є деяка різниця?
alpha_989

@ alpha_989, ось ваша відповідь: $ diff <(echo "Here are the letters in String One.") <(echo "Here are the characters in String Two.") \n 1c1 \n < Here are the letters in String One. \n --- \n > Here are the characters in String Two. \nВикористання труби подібне, за винятком того, що вона показує номер процесу, починається з наступного 1c1після наступного $і чекає, поки ви натиснете <kbd> Введіть <kbd> (або ви можете виконувати інші команди ...)
bballdave025

19

Нагадує мені таке запитання: як можна відрізняти два трубопроводи в Баші?

Якщо ви перебуваєте в сеансі баш, ви можете зробити:

diff <cmd1 <cmd2
diff <(foo | bar) <(baz | quux)

із <створенням анонімних іменованих труб - керованих bash - тому вони створюються та знищуються автоматично, на відміну від тимчасових файлів.

Тож якщо вам вдасться виділити дві різні рядки як частину команди (grep, awk, sed, ...), ви можете зробити, наприклад, щось на зразок:

diff < grep string1 myFile < grep string2 myFile

(якщо ви вважаєте, що у файлі є рядки типу string1=very_complicated_valuea і string2=another_long_and_complicated_value': не знаючи внутрішнього формату вашого файлу, я не можу рекомендувати точну команду)


13

Я віддаю перевагу cmpі обробляти функцію заміни bash:

$ cmp -bl <(echo -n abcda) <(echo -n aqcde)
  2 142 b    161 q
  5 141 a    145 e

Говорячи про положення 2, ab відбувається для першого, а aq для другого. У позиції 5 відбувається ще одна різниця. Просто замініть ці рядки змінними, і ви закінчите.


Це працює лише тоді, коли рядки однакової довжини!
strpeter

11

Скажіть, у вас є три струни

a="this is a line"
b="this is"
c="a line"

Щоб видалити префікс b з a

echo ${a#"$b"}  # a line

Щоб видалити суфікс c з a

echo ${a%"$c"}  # this is

2
Я здогадуюсь це невдалий спосіб зробити це. Це гарно працювало. Цей синтаксис трохи важко зрозуміти.
Мікаел Роос

@MikaelRoos Погодився. Простіше читати (для мене в будь-якому випадку) було б використовувати sed: echo "$a" | sed "s!^$b!!g" (Я поміняв стандартний сепаратор sed / /! У випадку, якщо змінні, з якими обробляються, є шляхами. Також, ви можете використовувати рядок тут замість echo:. sed ... <<< $a)
ACK_stoverflow

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