#Сначало пробую из консольного ввода
PS D:\> $a=$file | Select-String "^\[(.+)\]"
#Вывожу все заголовки
PS D:\> $a
[Headl1]
[Headl2]
[Headl3]
#Вывожу 2й заголовок
PS D:\> $a[1].Line
[Headl2]
#Вывожу номер строки в файле занимаемый 2ым заголовком
PS D:\> $a[1].LineNumber
83
#Пробую из свойства
PS D:\> $file.HeadlPrint
[Headl1]
[Headl2]
[Headl3]
PS D:\> $file.HeadlPrint[1].Line
[Headl2]
#А вот тут почему-то выдаёт не правильно
PS D:\> $file.HeadlPrint[1].LineNumber
1
Готовое решение на основе function Get-IniContent и function Out-IniFile не предлагать, оно путает порядок заголовков и ключей
Другие готовые решения которые я перепробовал не хотят работать с пустыми ключами ... то-есть на вот такой структуре крашется
Скажи пожалуйста, что заставляет тебя мучиться и выбирать в качестве языка программирования такой неудобный язык как powershell?
Твой приемник тебя проклянет за это, поддерживать твои скрипты никто не будет.
Не хочу оформлять ответом, вот тебе chatgpt что ответил
Проблема, с которой вы столкнулись, видимо, связана с тем, как PowerShell обрабатывает вывод тех объектов, которые появляются во время выполнения скрипта.
Одна из особенностей PowerShell - это то, что он не только выполняет операции и возвращает значения, но и создаёт объекты, которые представляют эти результаты. При выполнении операции Select-String, PowerShell создаёт объект MatchInfo для каждого совпадения, который содержит всю необходимую информацию, включая номер строки.
Однако, когда вы обращаетесь к свойству $file.HeadlPrint, PowerShell рассматривает каждую строку файла как отдельный объект. По этой причине каждая строка, соответствующая шаблону, имеет номер строки 1, потому что это первая (и единственная) строка в соответствующем объекте.
Один из способов решить эту проблему - хранить номер строки в собственном свойстве объекта и обновлять его при каждом нахождении нового заголовка.
Windows в своей поставке начиная с win7 (а с сервиспаками с winxp) таскает .net sdk, в котором компилятор c# js# vbs# размещен в C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ (там на самом деле несколько версий, точный путь в реестре).
Что может быть удобнее полноценного c# (без среды разработки но для powershell у вас тоже ее нет)?
Главный недостаток, этот путь универсально не получить, точнее нужно по реестру лазить. Но, так как новые версии устанавливаются по другому пути, эти уже давно не менялись (там даже 2-ая .net версия лежит) то это уже не проблема.
p.s. Не нравится .net?
Ок, windows таскает со времен winxp (может и раньше но там устанавливать нужно было) windows scripting host - можно писать скрипты на javascript или visual basic script
Да, возможно по доступу в дебри информации windows на powershell есть удобный инструментарий (просто потому что иначе другими способами до некоторой информации не добраться) но вот всякие манипуляции с датами и строками это гораздо удобнее
c# - я не хочу ничего компилировать в бинарники, хочу прямой доступ к скриптам чтоб в любой момент можно было поправить
js# - не удобная работа с файлами
vbs# - сначала пробовал на нём, получается большой не удобный громоздкий код
CMD(bat) - в принцепи не способен на такое
Не поленился (ка же это абсурдно звучит) ;) пнул chatgpt чтобы он написал пример:
main.cs
using System;
using System.IO;
using System.Collections.Generic;
class IniFile
{
private Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string, string>>(StringComparer.InvariantCultureIgnoreCase);
public IniFile(string filePath)
{
var txt = File.ReadAllText(filePath);
Dictionary<string, string> currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
ini[""] = currentSection;
foreach (var line in txt.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries))
{
var trimmedLine = line.Trim();
if (trimmedLine.StartsWith(";") || trimmedLine.StartsWith("#"))
{
continue;
}
if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]"))
{
var sectionName = trimmedLine.Substring(1, trimmedLine.Length - 2);
if (!ini.ContainsKey(sectionName))
{
currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
ini.Add(sectionName, currentSection);
}
}
else
{
var idx = line.IndexOf('=');
if (idx == -1)
continue;
var key = line.Substring(0, idx).Trim();
var value = line.Substring(idx + 1).Trim();
if (!currentSection.ContainsKey(key))
currentSection.Add(key, value);
}
}
}
public string GetValue(string section, string key)
{
if (!ini.ContainsKey(section))
return null;
if (!ini[section].ContainsKey(key))
return null;
return ini[section][key];
}
}
internal static class Program
{
public static void Main(string[] args)
{
// Создание нового объекта INIFile и запись некоторых данных в него
IniFile ini = new IniFile("test.ini");
// Чтение данных из того же INI файла
Console.WriteLine("value:='"+ini.GetValue("Headl1", "Key3")+"'");
}
}
Запуск с компиляцией (которая длится доли секунды):
del main.exe & C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /nologo main.cs & main.exe
Скажи пожалуйста, что заставляет тебя мучиться и выбирать в качестве языка программирования такой неудобный язык как powershell?
rPman, скажите, пожалуйста, что заставляет вас мучиться и лезть с непрошенными советами? К тому же - по чисто субъективному вопросу: "неудобный" - понятие чисто субъективное, да. Мне, к примеру, Powershell более удобен, чем JScript или VBScript (c которыми я тоже наработался). А что до C#, то чисто объективно, у C# как средства написания маленьких программок есть тот недостаток, что он - язык строго типизированный, а потому требует выполнять куда больше церемоний (AKA boilerplate), которые в маленьких программа неуместны.
PS Powershell, который, как и C#, работает поверх .NET CLR, кстати, позволяет делать и тут же компилировать и выполнять короткие вставки на C#. И при работе со старым Excnange этим приходилось пользоваться: кое-какие вещи тогдашний Powershell (являющийся безальтернативным средством администрирования Exchange) делать не умел. Но это уже совсем другая история.
rPman, отвратная громоздкая куита ... кому надо пусть пользуется
на powershell управился в 60 строк на с десяток команд
при этом реализовал , чтение запись и нормальную навигацию
$path = "D:\test.ini"
$INI = IniF($path)
$INI.PrintHeadls
$INI.SelectHeadl("Headl11")
$INI.PrintCurrentHl
$INI.SelectHeadlNext
$INI.PrintCurrentHl
$INI.PrintKeys
$INI.SelectKey("Key1")
$INI.PrintCurrentKey
$INI.EditKey("qwerty")
$INI.PrintFile
$INI.SaveFile