Цикл по массиву и основанный на одном значении столбца, согласовать другое значение столбца - PullRequest
0 голосов
/ 02 апреля 2019

Ниже приведены значения, которые у меня есть в массиве

10.106.86.93,A1,3
10.106.86.93,A2,3
10.106.86.93,A2,3
10.106.86.93,A3,3
10.106.86.93,A3,3
10.106.86.93,A4,3

Необходимо пройти через это, и если последнее значение равно 3, тогда необходимо объединить значение второго столбца

например.

10.106.86.93  A1,A2,A2,A3,A3,A4  3

пытался использовать цикл for, но не использовал правильно или нет

while read -r line
do
    StatusValue= $line | awk -F, '{print $NF}'
    if [[${StatusValue} == "3"}]] then
       echo $line | awk -F,'{print $2}'
    fi

done <<< ${Dell_Data_Status_3}

Здесь я пытаюсь напечатать второе значение строки, когда статус равен 3

но не в состоянии получить вывод.

ошибка:

./SortFile.sh: line 30: syntax error near unexpected token `fi'
./SortFile.sh: line 30: `    fi'

Пожалуйста, дайте мне знать, что здесь не так

Ответы [ 3 ]

2 голосов
/ 02 апреля 2019

Давайте начнем с простого синтаксиса bash:

Ниже приведены значения, которые у меня есть в массиве

Хорошо, у нас есть массив bash:

arr=(
10.106.86.93,A1,3
10.106.86.93,A2,3
10.106.86.93,A2,3
10.106.86.93,A3,3
10.106.86.93,A3,3
10.106.86.93,A4,3
)

Нужно пройти через это

Ok. Сначала нам нужно вывести массив в виде списка, разделенного новой строкой. Следующее выведет массив:

$ printf "%s\n" "${arr[@]}"

Затем нам нужно прочитать элементы массива и разделить их на разделитель запятых. Мы переменная IFS для управления тем, какие символы bash разделяет элементы:

printf "%s\n" "${arr[@]}" |
while IFS=, read -r ip A num; do
     : # TODO body
done

Ok. Теперь мы можем проверить значение третьего столбца и вывести третий, если оно соответствует 3:

printf "%s\n" "${arr[@]}" |
while IFS=, read -r ip A num; do
     if [ "$num" = 3 ]; then
          echo "$A"
     fi
done

Обратите внимание, что каждый пробел важен. if [[${StatusValue} == "3"}]] then из вашего кода очень недействительно - вам нужен пробел между [[ и ${.. и пробел между "3" и ]], } недопустим. Помните, что вы разговариваете с компьютером, используя клавиатуру, и больше ничего - каждое нажатие клавиши имеет значение.

Теперь самая сложная часть:

если последнее значение равно 3, тогда необходимо объединить значение второго столбца

Ну, это просто и быстро сделать с помощью awk сценариев. Что нам нужно сделать, это создать карту. Нам нужно отобразить значение третьего столбца на два других столбца.

Но давайте сделаем простой, глупый и очень, очень медленный подход:

  1. Определить уникальные значения в третьем столбце
  2. Для каждого уникального значения в третьем столбце
    1. Получить все строки с этим значением в качестве третьего столбца
    2. Получить первый столбец из любой строки
    3. Из отфильтрованных строк извлеките второй столбец и объедините их
    4. Вывести строку

# just to have the array as a string
arrstr=$(printf "%s\n" "${arr[@]}")

# cut only the third column and get unique values
<<<"$arrstr" cut -d, -f3  | sort -u |
# for each unique third column value
while read -r num; do
    # get the columns that have that value as the third column
    filtered=$(<<<"$arrstr" awk -vIFS=, -vOFS=, '$3 = '"$num")
    # get the values of the second field only
    # substitute newline for comma
    # remove the trailing comma
    second_field_sum=$(<<<"$filtered" cut -d, -f2 | tr '\n' ',' | sed 's/,$//')
    # get the value of the first field (from the first line)
    ip=$(<<<"$filtered" head -n1 | cut -d, -f1)
    # output
    printf "%s %s %s\n" "$ip" "$second_field_sum" "$num"
done

Пожалуйста, проверьте ваш скрипт на shellcheck.net на наличие ошибок. Ошибки большинства новичков (пропущенные кавычки, опечатки, неправильные перенаправления, синтаксические ошибки if) легко исправить, просто прослушав сообщения проверки оболочки.

1 голос
/ 02 апреля 2019

Заимствуя кое-что у @KamilCuk, заплатив долг с ++, спасибо:

$ arr=(
10.106.86.93,A1,3
10.106.86.93,A2,3
10.106.86.93,A2,3
10.106.86.93,A3,3
10.106.86.93,A3,3
10.106.86.93,A4,3
)

Использование awk для обработки:

$ printf "%s\n" "${arr[@]}" | 
awk -F, '                          # input separator to a comma
$3==3 {                            # when the third field is 3
    f2=$2=f2 (f2==""?"":",") $2    # update the $2 to 2nd field var f2 and
    out=$0                         # ... keep printable record in out var
}
END { print out }'                 # output here

Вывод:

10.106.86.93 A1,A2,A2,A3,A3,A4 3

И, конечно, эти данные могут быть в файле, а не в массиве.

Обновить по запросу:

$ printf "%s\n" "${arr[@]}" | 
awk -F, -v OFS=, '                 # input and output separators to a comma
$3==3 {                            # when the third field is 3
    f2=$2=f2 (f2==""?"":",") $2    # update the $2 to 2nd field var f2 and
    out=$0                         # ... keep printable record in out var
}
END { print out }'                 # output here
0 голосов
/ 02 апреля 2019

Вы можете сделать это в чистом bash (и GNU coreutils) с помощью этого скрипта:

#! /bin/bash
set -euo pipefail

# https://stackoverflow.com/questions/1527049
function join_by { local IFS="$1"; shift; echo "$*"; }

Dell_Data_Status_3="$(cat data)" # I made a standalone script and assume
                                 # this variable contains the raw data

# Get the list of first column elements, sorted and deduplicated
readarray -t first_col <<<"$(echo "${Dell_Data_Status_3}" | cut -d ',' -f 1 | sort -u)"

for i in "${first_col[@]}" ; do
    # get the values of the second column for every first column element
    readarray -t second_col <<<"$(echo "${Dell_Data_Status_3}" | grep "$i" | cut -d ',' -f 2)"

    # print the data. If you need another value than 3 at the end,
    # you may want to consider a loop on this value
    echo "$i $(join_by ',' "${second_col[@]}") 3"
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...