Разница строк в Bash

110

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

Я вижу, что comm, diff, cmp позволяют передавать либо два файла, либо файл и стандартный ввод - я думаю, это хорошо, если я не хочу выводить два файла ... но это все равно отстой.

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

codeforester
источник
1
что ты на самом деле хочешь делать?
Вы можете использовать манипуляции с подстроками и встроенные тестовые операции с изменениями IFS для сравнения, но вам нужно знать, хотите ли вы сравнивать символ за символом, слово за словом, строку за строкой, игнорировать пробелы ...
technosaurus

Ответы:

198

Используя diffили comили что угодно:

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

Часто задаваемые вопросы о Greg's Bash: подстановка процессов

или с именованным каналом

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

Greg's Bash FAQ: Работа с именованными каналами

Именованный канал также известен как FIFO.

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

<<< "здесь строка".

&похоже, ;но помещает его на задний план

Ян Келлинг
источник
5
+1 за правильный ответ. +1 за отличное объяснение символов. Кроме того, FAQ Грега по Bash перемещен по адресу : mywiki.wooledge.org Ссылки на указанные выше страницы теперь находятся на mywiki.wooledge.org/ProcessSubstitution и mywiki.wooledge.org/BashFAQ/085
timemachine3030
Спасибо! а также, это покажет динамические дескрипторы файловFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Водолей Сила
Я искал это для сравнения двух шасумов. Не уверен, что есть более элегантный способ сделать это, но он работает.
fuma
Кажется, это работает, если в $ 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> Enter <kbd> (или вы можете выполнять другие команды ...)
bballdave025
19

Напоминает мне вопрос: как можно различать два конвейера в Bash?

Если вы находитесь в сеансе bash, вы можете:

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

с <созданием анонимных именованных каналов - под управлением bash - поэтому они создаются и уничтожаются автоматически, в отличие от временных файлов.

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

diff < grep string1 myFile < grep string2 myFile

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

VonC
источник
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 происходит еще одно отличие. Просто замените эти строки переменными, и все готово.

Йоханнес Шауб - litb
источник
Это работает, только когда строки имеют одинаковую длину!
strpeter
11

Скажем, у вас три струны

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

Чтобы удалить префикс b из a

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

Чтобы удалить суффикс c из

echo ${a%"$c"}  # this is
Питикос
источник
2
Я думаю, это способ сделать это с помощью bash. Это отлично сработало. Однако этот синтаксис немного сложно понять.
Mikael Roos
@MikaelRoos Согласен. Легче читать (в любом случае для меня) было бы использовать sed: echo "$a" | sed "s!^$b!!g" (я заменил стандартный разделитель sed / на! На случай, если обрабатываемые переменные являются путями. Кроме того, вы можете использовать здесь строку вместо echo:. sed ... <<< $a)
ACK_stoverflow 08