Как удалить значения $ VAR2 из $ VAR1 и вывести оставшиеся значения в $ VAR3?

Не знаю, как получить "после канала", но "после третьего пробела" может помочь:

$ echo ,cats,and,dogs, | sed -e 's/,[^,]*,[^,]*,/,,,/'
,,,dogs,
$ echo ,cat,and,mouse, | !:3-$
,,,mouse,

Временное решение для "после канала" :

$ echo ,cats,and,dogs, | sed -e 's/,[^,]*,[^,]*,/,,,/'
,,,dogs,
$ after_pipe="$(cut -d "|" -f 2- <<<"!!" )"
$ echo ,cat,and,mouse, | eval "$after_pipe"
$ ,,,mouse,

( cut должен быть чем-то лучше, если в первой команде есть каналы в кавычках "|".)

2
26.09.2017, 15:12
2 ответа
> echo $VAR1 $VAR2 | tr ' ' '\n' | sort | uniq --unique | tr '\n' ' '
2 4
1
27.01.2020, 21:53

Первый, простой, но ограниченный вариант

VAR3=$(printf "%d\n" $VAR1 $VAR2 | sort | uniq -u | tr '\n' ' ' | sed 's/\s$//)

$ echo "$VAR3"
2 4

Основным недостатком является то, что :он оставляет только уникальные значения из переменной VAR1. То есть, если $VAR1имеет одно значение, повторяющееся несколько раз, это значение не появляется в $VAR3, потому что оно не уникально.

Пример:

VAR1="1 2 2 3 4 4 4 5"
VAR2="1 3 5"
# the resulting VAR3 variable is empty
VAR3 = "" # because it is containing only unique values and `2` and `4` repeated few times in the `VAR1`, therefore, they are not unique.

# The right result should be
VAR3 = "2 2 4 4 4" 

Второй, более универсальный и правильный вариант

VAR3=$(printf "%s\n" $VAR2 | awk -v var1="$VAR1" '
{arr2[$1] = 1;}

END {
    size = split(var1, arr1); 
    for(i = 1; i <= size; i++) {
        if(!arr2[arr1[i]]) 
            printf "%s ", arr1[i];
    }
}' | sed 's/\s$//')

Пояснение

  1. printf "%s\n" $VAR2-преобразует $VAR2в столбец -по одному значению в строке.
  2. awk...-удаляет значения $VAR2из $VAR1.

    • {arr2[$1] = 1;}-помещает все VAR2значения (, переданные в awkс помощью printf), в массив, где значения становятся индексами массива. = 1просто означает истинное-это значение существует. Этот трюк дает нам следующее поведение :первое вхождение значения создает элемент массива, затем, если то же значение появляется снова, оно переходит к тому же индексу массива, другими словами, элемент не изменяется, когда появляется то же значение несколько раз. Таким образом, в итоге мы имеем все уникальные значения из переменной VAR2. Если VAR2="one three five", то arr2будет :arr2[one] = 1, arr2[three] = 1, arr2[five] = 1.
    • END { size = split(var1, arr1);-когда строки ввода закончились(VAR2обработка завершена ), мы разбиваем VAR1на массив -каждое значение переходит в отдельный элемент. Если VAR1="one two three four five", то мы получим следующий массив :arr1[1] = one, arr1[2] = two, arr1[3] = three..., и так далее. Функция splitвозвращает размер нового созданного массива.
    • Затем
    • if(!arr2[arr1[i]]) printf "%s ", arr1[i];-перебирает arr1элементов и проверяет, имеет ли arr2индекс для этого элемента. Например :i = 1; arr1[1] = "one", тогда arr2[arr1[i]]это-arr2[one]. Этот элемент существует, не печатайте его. i = 2; arr1[2] = "two". arr2[two]не существует, так что выведите его. Таким образом, мы печатаем все значения из arr1, которых нет в arr2.
  3. sed 's/\s$//'-удаляет завершающий пробел.

Плюсы этого способа по сравнению с первым вариантом:

    # It can process strings
    VAR1="one two three four five"
    VAR2="one three five"
    # the resulting VAR3 variable
    VAR3 = "two four"

    # It doesn't remove multiple occurrence of one value in the VAR1
    VAR1="1 2 2 3 4 4 4 5"
    VAR2="1 3 5"
    # the resulting VAR3 variable
    VAR3 = "2 2 4 4 4"
2
27.01.2020, 21:53

Теги

Похожие вопросы