1

У меня есть две переменные: 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 без создания какого-либо файла?

3 ответа3

2

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

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

    #!/bin/bash
    var1="1, 2, 3, 4"; var2="3, 4, 5, 6"
    var3=$(echo " ${var1}, ${var2}" | 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 "${ADDR[@]}"; do
      Found=0
      for j in "${ADDR2[@]}"; 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 "${ADDR2[@]}"; do
      Found=0
      for i in "${ADDR[@]}"; 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 ',' '{for (i=1;i<=NF;i++) {A[$i]++;} } 
                    END{ SEP=""; 
                         for (i in A) {if (A[i]==1){
                            printf ("%s%s", SEP,i); SEP=", "} 
                         }
                       }'
          )
    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,
    
0

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

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

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

#!/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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .