Какие инструменты хорошо справляются с пробелами в столбчатых данных? - PullRequest
0 голосов
/ 25 августа 2011

Давайте начнем с примера, с которым я недавно столкнулся:

C:\>net user

User accounts for \\SOMESYSTEM

-------------------------------------------------------------------------------
ASPNET                   user1                    AnotherUser123
Guest                    IUSR_SOMESYSTEM          IWAM_SOMESYSTEM
SUPPORT_12345678         test userrrrrrrrrrrr     test_userrrrrrrrrrrr
The command completed successfully.

В третьем ряду второго столбца есть логин с пробелом.Это приводит к тому, что многие инструменты, которые разделяют поля на основе пробелов, рассматривают это поле как два поля.

Как бы вы поступили с данными, отформатированными таким образом с использованием современных инструментов?

Вот пример на чистом ** пакетном языке Windows в командной строке, который я хотел бы воспроизвести в других современных кроссплатформенных наборах инструментов для обработки текста:

C:\>cmd /v:on
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

C:\>echo off

for /f "skip=4 tokens=*" %g in ('net user ^| findstr /v /c:"The command completed successfully."') do (
More? set record=%g
More? echo !record:~0,20!
More? echo !record:~25,20!
More? echo !record:~50,20!
More? )
ASPNET
user1
AnotherUser123
Guest
IUSR_SOMESYSTEM
IWAM_SOMESYSTEM
SUPPORT_12345678
test userrrrrrrrrrrr
test_userrrrrrrrrrrr


echo on
C:\>

** Использование расширения с переменной задержкой(cmd / v: on или setlocal enabledelayedexpansion в пакетном файле), синтаксический анализатор вывода команды for / f и синтаксис переменной-подстроки ... ничего из этого хорошо документировано, за исключением замечательного веб-сайта http://ss64.com/nt/syntax.html

Заглядывая в AWK, я не видел способа справиться с полем входа 'test userrrrrrrrrrrr' без использования substr () в методе, аналогичном синтаксису подстроки переменных выше.Есть ли другой язык, который облегчает обработку текста и не предназначен только для записи, как sed?

Ответы [ 6 ]

1 голос
/ 26 августа 2011

PowerShell:

Пример собственного списка пользователей, соответствие текста не требуется

Get-WmiObject Win32_UserAccount | Format-Table -Property Caption -HideTableHeaders

Или, если вы хотите использовать "NET USER":

$out = net user     # Send stdout to $out
$out = $out[4..($out.Length-3)]     # Skip header/tail
[regex]::split($out, "\s{2}") | where { $_.Length -ne 0 }   
# Split on double-space and skip empty lines
0 голосов
/ 27 августа 2011

Для этой части:

set record=%g
More? echo !record:~0,20!
More? echo !record:~25,20!
More? echo !record:~50,20! 

Я бы использовал:

for /f "tokens=1-26 delims= " %a in (%g%) do (
if not "%a" = "" echo %a
if not "%b" = "" echo %b
if not "%c" = "" echo %c
rem ... and so on...
if not "%y" = "" echo %y
if not "%z" = "" echo %z
)

То есть, если бы мне пришлось делать это с помощью пакета. Но я бы не посмел назвать это "современным" по вашему вопросу.

0 голосов
/ 26 августа 2011

Awk не так хорош для этой проблемы, потому что awk ориентирован на строки как записи с распознаваемым разделителем полей, в то время как файл примера использует поля фиксированной ширины.Например, вы можете попытаться использовать регулярное выражение для разделителя полей, но это может пойти не так.Правильный способ будет использовать эту фиксированную ширину, чтобы очистить файл во что-то более простое для работы;awk может сделать это, но это не элегантно.

По сути, пример сложный, потому что он не следует четким правилам.Лучший подход довольно общий: записывать данные в файлы в четко определенном формате с помощью библиотечной функции, читать файлы с помощью дополнительной библиотечной функции.Конкретный язык не имеет большого значения с этой стратегией.Не то, чтобы это помогло, когда у вас уже есть файл, подобный примеру.

0 голосов
/ 26 августа 2011

Просто сделайте прямой запрос учетных записей пользователей, используя vbscript (или powershell, если ваша система поддерживает)

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_UserAccount",,48)
For Each objItem in colItems
    Wscript.Echo objItem.Name
Next

Это покажет вам список пользователей, по одному на строку. Если ваша цель просто показать имена пользователей, вам не нужно использовать другие инструменты для обработки данных.

0 голосов
/ 26 августа 2011

TEST

 printf "
User accounts for \\SOMESYSTEM

-------------------------------------------------------------------------------
ASPNET                   user1                    AnotherUser123
Guest                    IUSR_SOMESYSTEM          IWAM_SOMESYSTEM
SUPPORT_12345678         test userrrrrrrrrrrr     test_userrrrrrrrrrrr
The command completed successfully.
\n" | awk 'BEGIN{
        colWidth=25
       }
       /-----/ {next}
       /^[[:space:]]*$/{next}
       /^User accounts/{next}
       /^The command completed/{next}
       {
        col1=substr($0,1,colWidth)
        col2=substr($0,1+colWidth,colWidth)
        col3=substr($0,1+(colWidth*2),colWidth)
        printf("%s\n%s\n%s\n", col1, col2, col3)
       }' 

Возможно, есть лучший способ, чем 1+ (colWidth * 2), но сейчас у меня нет времени.

Если вы попытаетесь выполнить кодкак есть, вам придется удалить начальные пробелы в начале каждой строки в выражении printf.

Надеюсь, это поможет.

0 голосов
/ 26 августа 2011

Perl - действительно лучший выбор для вашего случая и миллионов других. Это очень распространено, и в Интернете полно примеров и документации. Да, он кроссплатформенный, чрезвычайно стабильный и практически идеально совместимый на разных платформах. Я говорю почти потому, что нет ничего идеального, и я сомневаюсь, что в вашей жизни вы столкнетесь с несоответствием.

Это интерпретатор языка, но также поддерживает богатый интерфейс командной строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...