Рекурсивный пакетный файл

826
MCZ

У меня есть файл, который выглядит так:

head1,head2,head3,head4,head5,head6 a11,a12,keyA,a14,a15,a16 a21,a22,keyB,a24,a25 a31,a32,keyC,a34 a41,a42,keyB,a44,a44 a51,a52,keyA,a54,a55,a56 a61,a62,keyA,a64,a65,a66 a71,a72,keyC,a74 some message 

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

KeyA, KeyB, KeyC

Вот псевдокод, который я хотел бы реализовать в командном файле recur.bat

  1. Прочитайте вторую строку входного файла
  2. Если во второй строке нет ключа, вернитесь иначе продолжить
  3. Добавить keyXв список
  4. FINDSTR /v keyX inputfile
  5. Труба результаты в recur.bat

Я не знаю, является ли это наиболее эффективным способом сделать это без использования реального языка программирования.

Любые предложения для фактического кода пакетного файла?

0
Добро пожаловать в Super User, MCZ! Итак, какой у тебя вопрос, правда? Вы застряли где-то реализации файла? Что вы уже придумали? Также, пожалуйста, проверьте предварительный просмотр ваших сообщений перед их отправкой - вам нужно сделать отступ кода на 4 пробела или нажав `Ctrl-K`. slhck 11 лет назад 1

3 ответа на вопрос

1
Bob

Вы можете использовать PowerShell, который поставляется с Windows Vista или более поздней версии:

$keys = @( ); Import-Csv input.txt | ForEach-Object {  if (!$_.head3) { $keys | Out-File output.txt; break; } else { if (!($keys -contains $_.head3)) { $keys += $_.head3; } } } 

Это может быть медленно для больших объемов данных, так как он использует array ( $keys) для хранения и проверки уникальных ключей. Альтернативный метод - записать все в текстовый файл, отсортировать и запустить его Get-Unique. Другой альтернативой является использование хеш-таблицы (не поможет с использованием памяти, но будет быстрее, чем проверка, существует ли что-то в массиве).

Это использует Import-Csv, который будет принимать первую строку в качестве заголовков. Затем он передает массив объектов (линий) в ForEach-Object. $_переменная, ссылающаяся на каждый объект (строку). .head3это свойство с именем head3, определенным в данных вашего примера как столбец, содержащий ключи. Он проверяет, есть ли значение для этого столбца в этой строке; если нет, то выводится в файл и завершается в соответствии с вашим псевдокодом. Обратите внимание, что неключевые значения могут быть приняты. Если у вас есть / нужны более строгие правила для того, что является ключом, вы можете проверить длину или выполнить какое-либо сопоставление с шаблоном RegEx и т. Д.

a71,a72,a73,a74 a71,a72,keyC,a74 some message a71,a72,keyD,a74 

В настоящее время a73считается ключом (он находится в третьем столбце head3). Программа закончится в some message, так как у нее нет третьего столбца, и она не будет прочитана keyD.

Если в строке есть столбец ключа, он проверяет, существует ли ключ в массиве, и, если нет, добавляет его. Обратите внимание, что -containsрегистр не учитывается. Если это проблема, ее можно изменить.

Так что вам, вероятно, придется заменить input.txt output.txtи head3правильными именами. Это было самое простое решение, которое не изменяет порядок данных, хотя при необходимости возможны более быстрые.

1
Bob

Отдельный ответ, потому что это, по сути, другое решение

Итак, вот cmd / пакетная версия.

@echo off type NUL>output.txt for /f "tokens=1,3 delims=, skip=1" %%a in (input.txt) do ( if "%%b"=="" goto :eof findstr "^%%b$" output.txt > NUL if ERRORLEVEL 1 echo %%b>>output.txt ) 

Он создает файл output.txt, затем читает файл input.txt, используя forи ,в качестве разделителя. Первая строка пропущена.

Первый token ( tokens=1,3) нужно было прочитать, чтобы остановить его в some messageстроке, поскольку он просто пропустил бы строку и продолжил, если запрошенный token ( tokens=3) не существовал - и никогда не запустил бы if. %%aявляется первым запрошенным токеном ( 1), %%bявляется вторым ( 3).

a71,a72,a73,a74 a71,a72,keyC,a74 some message a71,a72,keyD,a74 

keyDне будет прочитано, так как останавливается на строке раньше (не имеет третьего токена). Тем не менее, a73будут засчитаны.

Он использует findstrвыходной файл, чтобы проверить, есть ли уже там ключ - не эффективен ли вообще, но он работает. RegEx используется, чтобы убедиться, что он соответствует всей строке; если один ключ полностью содержится в другом ключе, он не будет совпадать (т.е. keyAне будет совпадать key). Выходные данные направлены на то, NULчтобы сохранить спокойствие.

И если ключа нет в выходном файле, он добавит его.

0
Michael S.

В Bash (вы можете использовать Cygwin, если вы используете Windows) это легко:

1.) заменить на новую строку (\ n)

sed -i 's/,/\n/g' superuser.txt 

Прежде чем вы имели:

head1,head2,head3,head4,head5,head6 a11,a12,keyA,a14,a15,a16 a21,a22,keyB,a24,a25 a31,a32,keyC,a34 a41,a42,keyB,a44,a44 a51,a52,keyA,a54,a55,a56 a61,a62,keyA,a64,a65,a66 a71,a72,keyC,a74 

Теперь у вас есть:

head1 head2 head3 head4 head5 head6 a11 a12 keyA a14 a15 a16 a21 a22 keyB a24 a25 a31 a32 keyC a34 a41 a42 keyB a44 a44 a51 a52 keyA a54 a55 a56 a61 a62 keyA a64 a65 a66 a71 a72 keyC a74 

2.) Поиск «ключа», сортировка результатов и устранение дубликатов

grep -F key superuser.txt | sort | uniq 

Дает тебе:

keyA keyB keyC 
Я почти уверен, что файл OP не был в одной строке, они просто неправильно форматировали. Смотрите обновленный вопрос. slhck 11 лет назад 0
Нужно использовать собственные команды Windows. MCZ 11 лет назад 0
keyX = шестнадцатеричное значение (строка) в диапазоне от 0000 до FFFF. Поэтому слово «ключ» не содержится ни в одной строке столбца 3. MCZ 11 лет назад 0
@MCZ Включает ли это PowerShell? потому что, хотя это может быть возможно с `for` в cmd, PowerShell определенно будет« чище ». Bob 11 лет назад 0
@ Боб ... К сожалению, мне нужно использовать команды, которые поставляются с Windows. Любые сторонние инструменты нуждаются в привилегиях администратора, которых у меня нет. MCZ 11 лет назад 0
Кстати, файлы, с которыми я работаю, имеют размер примерно 1/2 ГБ. MCZ 11 лет назад 0
@MCZ PowerShell поставляется с Vista и новее. Bob 11 лет назад 0
@ Боб ... Посмотрим на это. Не использовал PowerShell. Я новичок в использовании пакетных файлов, не знаю синтаксис для моего решения. Если я использую PowerShell, какие команды вы порекомендуете? Общий подход вы бы выбрали? Самое эффективное решение, которое у меня есть, на чтение файла размером 500 МБ занимает около 15 секунд (с помощью функции сканирования текста MATLAB). MCZ 11 лет назад 0