Извлечь и изменить определенные строки из текстового файла

Есть текстовый файл сетевых интерфейсов:

auto eth0 bri0
iface eth0 inet static
    address 192.168.1.118/24
iface eth0.110 inet manual
    vlan-raw-device eth0
iface bri0 inet static
    address 192.168.110.1/24
    bridge_ports eth0.110
    bridge_stp on
    bridge_maxwait 10 ```

Необходимо взять адрес у eth0 и заменить его на другой, например 192.168.1.13.

Я сделал класс, который получает все интерфейсы и ip:

 public class IpChangeService
{
    private readonly string[] configFile;
    private List<string> interfaceName = new List<string>();
    private List<string> ipAddress = new List<string>();
    private string currentAdapter;

    public IpChangeService(string[] configFile, string currentAdapter)
    {
        this.configFile = configFile;
        this.currentAdapter = currentAdapter;
    }

    public (IList<string> iface, IList<string> ipAddress) GetCurrentInterfaces()
    {
        foreach (var line in configFile)
        {
            if (line.Contains("iface") && line.Contains("inet static"))
            {
                if (interfaceName != null)
                {
                    var str = line.Split(' ')[1] + " ";
                    var strWithoutSpaces = str.Replace(" ", "");
                    interfaceName.Add(strWithoutSpaces);
                }
            }

            if (interfaceName!=null && line.Contains("address"))
            {
                // see http://stackoverflow.com/questions/4890789/regex-for-an-ip-address
                ipAddress.Add(Regex.Match(line, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}").Value);
            }
        }

        return (interfaceName, ipAddress);
    }

    public int GetCurrentInterfaceIndex()
    {
        return interfaceName.IndexOf(currentAdapter);
    }

Ну а в основной программе получаю данные и пытаюсь записать, но чувствую, что так не правильно, к тому же не работает нормально (криво вставляет адрес)! И пока не знаю, как правильно выделить ip без хардкода по индексу.

iface eth0 inet static
    address 192.168.1.118/24168.1.13/24

 private static void Main(string[] args)
    {
        var fileName = $"{AppDomain.CurrentDomain.BaseDirectory}interfaces";
        var inputLines = File.ReadAllLines(fileName, Encoding.Default);
        string interfaceName;
        string ipAddress;
        var ipChangeService = new IpChangeService(inputLines, "eth0");

        var currentIface = ipChangeService.GetCurrentInterfaces();
        var index = ipChangeService.GetCurrentInterfaceIndex();

        interfaceName = currentIface.iface[index];
        ipAddress = currentIface.ipAddress[0]; //FIXME: ХАРДКОД! 

        Console.WriteLine(interfaceName);

        var s2 = "192.168.1.113/24"; // ip на который заменяем строчку

        var configText = File.ReadAllText(fileName, Encoding.Default);

        configText = configText
            .Remove(configText.IndexOf(currentIface.ipAddress[0], StringComparison.Ordinal), ipAddress.Length)
            .Insert(configText.IndexOf(currentIface.ipAddress[0], StringComparison.Ordinal), s2);

        using (var file = new StreamWriter(fileName))
        {
            file.Write(configText);
        }
        Console.ReadKey();
    }

Но самое главное, не понятно, как выделить ip адрес именно eth0 из всех существующих (их может быть несколько). А после заменить именно эту подстроку.


Ответы (2 шт):

Автор решения: OXYGEN

Попробуй вот так :

На Входе

на входе

private void button2_Click(object sender, EventArgs e)
    {
        string searchFor = "iface eth0";

        bool IsFoundIface = false;
        string path = "data.txt";

        int foundindex=0;
        string port="";
        int size;


        if (File.Exists(path))
        {
            var dataFile = File.ReadAllLines(path);
            size= dataFile.Length;

            for (int i = 0; i < dataFile.Length; i++)
            {
                if (dataFile[i].IndexOf(searchFor, StringComparison.Ordinal) != -1)
                {
                    IsFoundIface = true;
                }
                if (IsFoundIface && dataFile[i+1].IndexOf("address", StringComparison.Ordinal) != -1)
                {
                    var splitonport = dataFile[i + 1].Split('/');
                    foundindex = i + 1;
                    port = splitonport[1];
                    break;
                }

            }
            string[] newData = new string[size];
            for (int i = 0; i < size; i++)
            {
                if (i != foundindex)
                {
                    newData[i] = dataFile[i];
                }
                else
                {
                    newData[i] = string.Format("      address {0}/{1}", textBox1.Text, port);
                }
            }

            File.WriteAllLines(path,newData);
        }

    }

на выходе получаем

auto eth0 bri0
iface eth0 inet static
      address 192.168.1.13/24
iface eth0.110 inet manual
    vlan-raw-device eth0
iface bri0 inet static
    address 192.168.110.1/24
    bridge_ports eth0.110
    bridge_stp on
    bridge_maxwait 10 ```
→ Ссылка
Автор решения: EvgeniyZ

Если надо просто заменить, то можно поступить так:

  • Делаем метод для поиска строчки с Ip:

    private static (string Line, int Index) GetIp(IList<string> lines, string search)
    {
        var adresses = lines.Select((Line, Index) => (Line, Index)).Where(x => x.Line.Contains("address"));
        foreach (var item in adresses)
        {
            for (int i = item.Index; i >= 0; i--)
            {
                if (lines[i].Contains(search))
                {
                    return item;
                }
            }
        }
    
        return default;
    }
    

    Поясняю:

    1. Преобразовываем все строчки в (значение, индекс) и забираем только те, которые имеют address. В результате у нас будут все строки с ip адресами и их индекс в списке.
    2. Сопоставляем ip с интерфейсами - просто пробегаем циклом for от места, где строчка с ip и до искомой строки вверх. Если интерфейс подходит под искомый, то возвращаем ip и его индекс.
  • Дальше все просто:

    • Считываем из файла все построчно:

      var lines = File.ReadAllLines("File.txt"); 
      
    • Находим нужный нам ip:

      var (Line, Index) = GetIp(lines, "iface eth0");
      
    • Меняем в строке ip адрес:

      lines[Index] = lines[Index].Replace(Line.Split().LastOrDefault(), "0.0.0.0");
      
    • Ну, осталось сохранить:

      File.WriteAllLines("File.txt", lines);
      

Результат:

auto eth0 bri0
iface eth0 inet static
    address 0.0.0.0
iface eth0.110 inet manual
    vlan-raw-device eth0
iface bri0 inet static
    address 192.168.110.1/24
    bridge_ports eth0.110
    bridge_stp on
    bridge_maxwait 10 ```
→ Ссылка