bash - найти разницу между двумя переменными

1757
Lejour

У меня есть две переменные: var1="1, 2, 3, 4"и var2="3, 4, 5, 6".
Я хотел бы получить новый, var3, содержащий различия между $var1и $var2.
Ожидаемый результат должен быть var3=1, 2, 5, 6.

Я пытался, diffно вывод не то, что я хотел:

diff <(echo "$var1") <(echo "$var2") 
1c1 < 1, 2, 3, 4 --- > 3, 4, 5, 6 

Какое другое решение позволяет мне var3без создания какого-либо файла?

1
Несколько дополнительных советов ... Наслаждайтесь SuperUser и `bash` ... Hastur 6 лет назад 0

3 ответа на вопрос

2
Hastur

Есть много способов...

  • Вы можете использовать sort, tr uniqueи pasteи $()выполнить их и «преобразования вывода в переменную»

    #!/bin/bash var1="1, 2, 3, 4"; var2="3, 4, 5, 6" var3=$(echo " $, $" | tr ',' '\n' | sort | uniq -u | paste -sd,) echo $var3 
    1, 2, 5, 6 

    Для каждой из предыдущих команд вы можете прочитать больше, например, man sort

  • Вы можете преобразовать переменную в массивах bash и поработать с ними (используйте подсказку как подсказку, потому что существует бесчисленное множество способов реализовать ее ...)

    #!/bin/bash#!/bin/bash var1="1, 2, 3, 4"; var2="3, 4, 5, 6"  # here you transform the variable in array IFS=',' read -ra ADDR <<< "$var1"  IFS=',' read -ra ADDR2 <<< "$var2"  # then for each element in the 1st array you search if in the 2nd too SEP=""; var3="" for i in "$"; do Found=0 for j in "$"; do [[ "$i" -eq "$j" ]] && Found=1 done  [[ $Found == 0 ]] && { var3="$var3$SEP$i" ; SEP=", "; } done  # then for each element in the 2nd array you search if in the 1st too for j in "$"; do Found=0 for i in "$"; do [[ "$i" -eq "$j" ]] && Found=1 done  [[ $Found == 0 ]] && { var3="$var3$SEP$j" ; SEP=", "; } done  echo $var3 
  • используя awk(или, если быть точным gawk)

    #!/bin/bash var1="1, 2, 3, 4"; var2="3, 4, 5, 6" var3=$(echo "$var1, $var2" | \ awk -F ',' ' }  END{ SEP="";  for (i in A)  } }' ) echo $var3 

Примечание: второй и третий выходы не упорядочены ...


Обновленные примечания : ... и до $var1и $var2потому, что в вашем странном ( :-)) формате есть пробелы после запятой ( ,), поэтому вам нужно уделить особое внимание всем командам, в которых в качестве разделителя используется только один символ ... это исправляет проблема, если , 1во второй строке было ... то, что вы не можете найти, man <command>вы можете попытаться найти с man bashили help command...

До тошноты :

  • diffстиль, в духе вашей попытки ... может быть, вы можете найти выходной формат более уютно ( man diff)

    diff --ignore-all-space \  <(echo "$var1" | tr ',' '\n' ) <(echo "$var2" | tr ',' '\n')\ | grep -v "^---" | grep -v "^[0-9c0-9]" | tr -d '<||>|| |' \ | paste -sd, 
Спасибо! Прекрасно работает с учетом специальных символов. Lejour 6 лет назад 0
@Lejour Добро пожаловать ... и добро пожаловать в SuperUser. Даже другие ответы, кажется, работают. Попробуйте и подтвердите ответы, которые вы найдете правильными и полезными. Выберите тот, который вы предпочитаете в качестве ответа на свой вопрос, и наслаждайтесь сайтом. Hastur 6 лет назад 0
0
glenn jackman

У меня нет времени на полное объяснение, но:

var1="1, 2, 3, 4"; var2="3, 4, 5, 6" comm -3 <(grep -oP '\d+' <<<"$var1" | sort) <(grep -oP '\d+' <<<"$var2" | sort) | tr -d '\t' | paste -sd, 
1,2,5,6 
0
Jaroslav Kucera

Другой вариант:

#!/usr/bin/bash  var1="1, 2, 3, 4" var2="3, 4, 5, 6" out=""  for num in `echo $var1,$var2 | tr -d " "| tr "," "\n " | sort | uniq | tr "\n" " "` do if (`grep -v $num <<< "$var1" >/dev/null 2>&1` || `grep -v $num <<< "$var2" >/dev/null 2>&1`) then out="$out,$num" fi done  echo $out | sed -e 's/,//' 

И беги

$ ./test.sh  1,2,5,6