удаление хостов из файла с разделителями-запятыми - PullRequest
2 голосов
/ 21 апреля 2020

Я пытаюсь написать способ удаления хостов из файла группы хостов в Nag ios Core. Формат файла группы узлов:

server1,server2,server3,server4

При удалении сервера мне нужно иметь возможность не только удалить сервер, но и запятую, которая следует за ним. Таким образом, в моем примере выше, если я удаляю server2, файл будет выглядеть следующим образом

server1,server3,server4

Так что я погуглил и протестировал следующее, которое работает для удаления server2 и запятой после него (я не точно знать, для чего используется b)

sed -i 's/\bserver2\b,//g' myfile

Что я хочу сделать, это передать список имен хостов небольшому сценарию, чтобы удалить группу хостов (и их следующую запятую) с помощью что-то похожее на следующее. Проблема заключается в том, что размещение переменной типа $ x нарушает работу сценария, так что ничего не происходит.

#!/bin/ksh
for x in `cat /tmp/list`
do
sed -i 's/\b${x}\b,//g' myfile
done

Я думаю, что я очень близок к решению здесь, но мог бы воспользоваться небольшой помощью. Заранее большое спасибо за вашу помощь.

Ответы [ 5 ]

2 голосов
/ 21 апреля 2020

Это прекрасно работает:

#!/bin/bash
IN_FILE=$1
shift; sed -i "s/\bserver[$@],*\b//g" $IN_FILE; sed -i "s/,$//g" $IN_FILE

если вы вызовете его как ./remove_server.sh myfile "1 4" для вашего файла примера, содержащего server1,server2,server3,server4, вы получите следующий вывод:

server2,server3

Краткое объяснение того, что он делает:

  • shift сдвигает аргументы вниз на один (убедившись, что "myfile" не передается в регулярное выражение)
  • Первый sed удаляет сервер с номерами, указанными в качестве аргументов в строке (например, «1 4»)
  • Второй sed ищет запятую и удаляет ее
  • \b соответствует границе слова

Это отличный ресурс для изучения и тестирования регулярных выражений: https://regex101.com/r/FxmjO5/1. Я бы порекомендовал вам проверить это и использовать каждый раз, когда у вас есть проблемы с регулярными выражениями. Это помогло мне во многих случаях!

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

Я опробовал его на этом файле:

# This is some file containing server info:
# Here are some servers:
server2,server3

# And here are more servers:
server7,server9

с ./remove_server.sh myfile "2 9" и получил это:

# This is some file containing info:
# Here are some servers:
server3

# And here are more servers:
server7
2 голосов
/ 21 апреля 2020

Использование одинарных кавычек говорит оболочке не заменять $ {x} - она ​​отключает интерполяцию переменных, если вы хотите найти ее в Google. https://www.tldp.org/LDP/abs/html/quotingvar.html. Поэтому вместо строки замены sed используйте двойные кавычки:

while read -r x; do sed -i "s/\b${x},\b//g" myfile; done < /tmp/list

Но поскольку в последнем поле после запятой не будет запятой, возможно, было бы неплохо запустить две команды sed, одна из которых ищет \ bword , \ b и другое для слова $ - где \ b - это граница слова, а $ - конец строки.

while read -r x; do sed -i "s/\b${x},\b//g" myfile; sed -i "s/,${x}$//" myfile ; done < /tmp/list

Еще одно возможное граничное условие - что делать, если в строке просто server2 само собой и это то, что вы пытаетесь удалить? Возможно, добавьте третий sed, но этот оставит пустую строку, за которой вы можете удалить:

while read -r x
do
  sed -i "s/\b${x},\b//g" myfile  # find and delete word,
  sed -i "s/,${x}$//" myfile      # find and delete ,word
  sed -i "s/^${x}$//" myfile      # find word on a line by itself
done < t
1 голос
/ 21 апреля 2020

Уверен, что для этого есть чистое sed решение, но вот скрипт.

#!/usr/bin/env bash

hosts=()

while read -r host; do
  hosts+=("s/\b$host,\{,1\}\b//g")
done < /tmp/list

opt=$(IFS=';' ; printf '%s' "${hosts[*]};s/,$//")

sed "$opt" myfile
  • Он не запускается sed построчно, но только один sed вызов. На всякий случай, скажем, вам нужно удалить шаблон 20+, тогда sed не будет запускаться и 20+ раз.

  • Добавьте -i, если вы считаете, что вывод в порядке.

0 голосов
/ 21 апреля 2020
Сценарий

bash, который считывает серверы для удаления из стандартного ввода, по одному на строку, и использует perl для удаления их из файла хоста (передается в качестве первого аргумента скрипту):

#!/usr/bin/env bash
# Usage: removehost.sh hostgroupfile < listfile

mapfile -t -u 0 servers
IFS="|"
export removals="${servers[*]}"
perl -pi -e 's/,?(?:$ENV{removals})\b//g; s/^,//' "$1"

Он считывает серверы для удаления в массив, объединяет их в строку, разделенную каналом, а затем использует это в регулярном выражении perl для удаления всех серверов за один проход через файл. Косые черты и другие забавные символы (если они не являются метасимволами RE) не будут портить синтаксический анализ perl, поскольку он использует переменную окружения вместо непосредственного встраивания строки. Также используется слово boun dry, поэтому удаление server2 не удалит эту часть server22.

0 голосов
/ 21 апреля 2020

Использование perl и регулярное выражение путем установки серверов в группу регулярных выражений в переменной оболочки:

$ remove="(server1|server4)"
$ perl -p -e  "s/(^|,)$remove(?=(,|$))//g;s/^,//" file
server2,server3

Объяснено:

  • remove="(server1|server4)" или "server1" или даже "server."
  • "s/(^|,)$remove(?=(,|$))//g" в двойных кавычках, чтобы разрешить переменные оболочки, удалить начальную запятую, за которой, как ожидается, следует запятая или конец строки
  • s/^,// file удалить начальную запятую, если первая запись была удалена

Используйте переключатель -i для редактирования инфилей.

...