Удаление строки Bash на нескольких массивах - PullRequest
0 голосов
/ 10 декабря 2011

У меня в bash два массива, каждый из которых содержит файлы. В моем цикле иногда файл удаляется. Всякий раз, когда это происходит, один из массивов показывает старое состояние, а другой - новое состояние. Как мне удается показать разницу между ними, e. г. какой именно файл был удален? Кстати, другого способа узнать нет.

Вот пример:

arr_a=( file1.txt file2.txt file3.txt )
arr_b=( file1.txt file3.txt )

#Now the output should be file2.txt

Я представил что-то ненормальное echo ${arr_a[@]#arr_b[@]}, но это не сработало. (Это приводит к тому, что arr_a выводится полностью.)

Ответы [ 3 ]

1 голос
/ 10 декабря 2011

Это немного сложно, но будет работать, если массивы не поддерживают корреляцию. Он сортирует все элементы большего массива для сопоставления с элементами более короткого массива, а затем печатает оставшиеся элементы в большем массиве (он работает с копиями массивов). Не полностью протестирован:

#!/bin/bash
arr_a=( file1.txt file2.txt file3.txt )
arr_b=( file1.txt file3.txt )

sortarr() {
    local sorted=( ${!1} ) sortby=( ${!2} )
    local length=${#sorted[@]} i=${#sortby} matches
    while (( i-- )); do
        [[ ! "${sorted[@]}" =~ ${sortby[$i]} ]] && continue
        sorted=( ${sorted[@]//$BASH_REMATCH/} )
        printf -v matches '%*s' $(( $length - ${#sorted[@]} ))
        sorted=( ${matches// /$BASH_REMATCH }${sorted[@]} )
    done
    for (( i=${#sortby[@]}; i<${#sorted[@]}; i++ )); do
        echo ${sorted[$i]}
    done
}

if (( ${#arr_a[@]} > ${#arr_b[@]} )); then
    sortarr arr_a[@] arr_b[@]
else
    sortarr arr_b[@] arr_a[@]
fi
0 голосов
/ 10 декабря 2011

Это может сработать для вас:

arr_a=(file1.txt file2.txt file3.txt)
arr_b=(file1.txt file3.txt)
answer=$(comm -3 <(printf "%s\n" "${arr_a[@]}") <(printf "%s\n" "${arr_b[@]}")
echo "$answer"
file2.txt

Возможно, было бы разумно быть немного более устойчивым:

arr_answer=($(comm -3 <(printf "%s\n" "${arr_a[@]}") <(printf "%s\n" "${arr_b[@]}") | paste -sd' '))
((${#arr_answer[@]}==1)) && echo "$arr_answer" || echo "oops! wrong answer"
0 голосов
/ 10 декабря 2011

@ Дэвид: Что вам в основном нужно, так это разница между двумя сетами. Это можно сделать намного проще, используя немного Python, как показано в методе 0 ниже. Метод 1 и 2 - это всего лишь два варианта, использующие индексированный и разреженный массив Bash. Выход для каждого из следующих методов: file2.txt

Метод-0:

#!/bin/bash

arr_a=( file1.txt file2.txt file3.txt )
arr_b=( file1.txt file3.txt )

echo -e "${arr_a[@]} \n ${arr_b[@]}" | python -c '\
    a=set(raw_input().strip().split());\
    b=set(raw_input().strip().split());\
    (x,y)=(a,b) if len(a)>len(b) else (b,a);\
    print "".join(list(x-y));'

Способ-1:

#!/bin/bash

arr_a=( file1.txt file2.txt file3.txt )
arr_b=( file1.txt file3.txt )
i=0

for a in ${arr_a[@]}
do
    AinB=0
    for b in ${arr_b[@]}
    do
        if [[ $a == $b ]]
        then
            AinB=1
        fi
    done

    if [[ AinB -eq 0 ]]
    then
        arr_c[$((i++))]=$a
    fi
done

echo ${arr_c[@]}

Способ-2:

#!/bin/bash

arr_a="file1.txt file2.txt file3.txt"
arr_b="file1.txt file3.txt"
arr_c=""

for a in $arr_a
do
    isPresentInB=0
    for b in $arr_b
    do
        if [[ $a == $b ]]
        then
            isPresentInB=1
            break
        fi
    done

    if [[ $isPresentInB -eq 0 ]]
    then
        arr_c="$arr_c $a"
    fi
done

echo $arr_c
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...