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

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

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

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

3 ответа3

1

Вы можете использовать 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;
        }
    }
}

Это может быть медленно для больших объемов данных, так как он использует массив ($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

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

Итак, вот 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 и , в качестве разделителя. Первая строка пропущена.

Первый токен (tokens=1,3) необходимо прочитать, чтобы остановить его в some message строке сообщения , так как он просто пропустит строку и продолжит работу, если запрошенный токен (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

В 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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .