Как проверить, равна ли строка другой строке на основе подстроки в Bash

Я пытаюсь сделать следующее:

У меня есть этот файл с именем testing.txt, который я хочу обновлять каждый раз, когда IP-адрес или адреса меняются в зависимости от имени (test1ip, test2ip):

127.0.0.1 localhost
somotherrandomip testing
192.168.0.36 test1ip
192.168.0.37 test2ip

Это то, что я пробовал.

#!/bin/bash
array=(
        "192.168.0.34 test1ip"
        "192.168.0.35 test2ip"
)

for i in "${array[@]}"; do
        if ! grep -Fxq "$i" testing.txt
        then
                echo "ip-name=$i is not present, so adding it in testing.txt file" 
                echo "$i" >> testing.txt
        else
                echo "ip-name=$i is present in file, so nothing to do"
        fi
done

Однако этот сценарий добавляет совершенно новую строку, если строка не найдена. Чего я хотел бы добиться, так это перезаписать строку, если test1ip или test2ip найдены, но IP-адрес изменился.

Ожидаемый результат:

127.0.0.1 localhost
somotherrandomip testing
192.168.0.34 test1ip
192.168.0.35 test2ip

Я также читал этот Как проверить, содержит ли строка подстроку в Bash, но, кажется, я не могу понять.

Любая помощь приветствуется!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
97
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вот решение bash + awk, которое эффективно справится с этой задачей:

#!/bin/bash

array=(
    "192.168.0.34 test1ip"
    "192.168.0.35 test2ip"
    "192.168.0.33 test3ip"
)

awk '
    FNR == NR {
        aarr[$2] = $1
        next
    }
    ! ($2 in aarr)
    END {
        for (host in aarr)
            print aarr[host], host
    }
' <(printf '%s\n' "${array[@]}") testing.txt
127.0.0.1 localhost
somotherrandomip testing
192.168.0.33 test3ip
192.168.0.34 test1ip
192.168.0.35 test2ip

примечания:

  • bash<( commands ) называется процесс-подстановка. Он создает файл, содержащий вывод commands, который вы можете использовать в качестве аргумента.

  • awk's FNR == NR — это условие выбора первого файлового аргумента. В этом блоке я создаю ассоциативный массив, который преобразует имя хоста в его новый IP-адрес.

  • ! ($2 in aarr) означает печатать записи, для которых имя хоста нет в массиве перевода.

  • END предназначен для печати массива перевода (новые IP-адреса имен хостов).

Спасибо @Fravadona за вашу помощь и время.

chiko 23.03.2022 01:04
Ответ принят как подходящий

На моей машине работает следующее. Я изменил массив на ассоциативный, удалил параметр -x для grep и использовал sed для редактирования файла на месте.

#!/bin/bash

#associative array
declare -A array=(
        [test1ip] = "192.168.0.34"
        [test2ip] = "192.168.0.35"
)

#Loop over keys of the array
#See parameter expansion in bash manpage
for i in "${!array[@]}"; do
        if ! grep -Fq "$i" testing.txt
        then
                echo "ip-name=$i is not present, so adding it in testing.txt file" 
                echo "${array[$i]} $i" >> testing.txt
        else
                echo "ip-name=$i is present in file so running sed"

                #Escape sed left hand side
                #Adapted for extended regular expressions from https://unix.stackexchange.com/a/129063/309759
                i=$(printf '%s\n' "$i" | sed 's:[][\/.^$*+?(){}|]:\\&:g')

                #Excape right hand side
                ipaddr=$(printf '%s\n' "${array[$i]}" | sed 's:[\/&]:\\&:g;$!s/$/\/')

                #Replace old IP vith new IP
                sed -Ei "s/[0-9]+(\.[0-9]+){3} +$i/$ipaddr $i/" testing.txt
        fi
done

Спасибо @Nathan за помощь в этом.

chiko 23.03.2022 01:04

Возможно, вам придется экранировать имена хостов, чтобы использовать их в sed в качестве строковых литералов; например example.test будет соответствовать examplestest. Кроме того, хотя вы правильно исправили код @chiko, вы не указали, что следует избегать использования grep и sed внутри цикла for.

Fravadona 23.03.2022 08:00

Другие вопросы по теме