Разделить файл с шаблоном в сценарии UNIX - PullRequest
0 голосов
/ 30 октября 2018

У меня есть файл, который я хотел бы разделить. Файл будет иметь заголовок и запись об ошибке. Тело файла содержит записи NFD и IV. IV записи не являются обязательными. Внутри записи NFD оно будет содержать где-то слово «английский» или «французский» или «французский». Для английского я бы хотел, чтобы NFD и IV перешли на en.txt, иначе перешли на fr.txt.
Вот пример:

 1. 000000000000000;HDR;1;...
 2. 000000008651776;NFD;Individual;...;English;...
 3. 000000008651776;IV;....
 4. 000000008657876;NFD;Individual;...;English;...
 5. 000000008751796;NFD;Individual;...;French;...
 6. 000000008751796;IV;...
 7. 999999999999999;TRL;...

Я бы хотел, чтобы все строки 1, 2, 3, 4, 7 перешли на en.txt, а строки 1, 5, 6, 7 - на fr.txt
Есть предложения по использованию скрипта K-shell? Спасибо!

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Я верю, что это сделает то, что вы хотите. Это было написано в ksh для Linux, но будет работать с bash или другими в большинстве версий Unix.

#!/bin/ksh
rm -f english.out
rm -f french.out
output=both
while read linein
do
    echo $linein | grep HDR     >/dev/null && output=both
    echo $linein | grep English >/dev/null && output=english
    echo $linein | grep French  >/dev/null && output=french
    echo $linein | grep TRL     >/dev/null && output=both
    case $output in
    both)
        echo "$linein" >> english.out
        echo "$linein" >> french.out
    ;;
    english)
        echo "$linein" >> english.out
    ;;
    french)
        echo "$linein" >> french.out
    ;;
    esac
done < data.txt

Для пояснения:

  1. Удалите старые выходные файлы при запуске.
  2. Установите для переменной output оба значения.
  3. Цикл while читает файл data.txt, по одной строке за раз в переменную linein. (Цикл while...done имеет ввод, перенаправленный из файла data.txt.)
  4. (Некоторые люди сочтут это неопрятным) Мы повторяем каждую строку в grep, отбрасывая вывод и сохраняя только статус выхода. Если статус выхода успешен, мы устанавливаем вывод. Если статус выхода равен false, мы не меняем вывод. Это позволяет нам отправлять записи NFD в то же место, что и предыдущая запись.
  5. Случай переключается между различными значениями вывода, чтобы решить, куда отправить вывод. Я ожидаю, что вы знаете, что >> означает добавление вывода в файл. Соблюдайте кавычки вокруг $linein. Если их там нет, вы не сохраните пробелы во входных данных. Это не имеет значения в вашем случае.

Если вы хотите искать только английский или французский в поле 5, оно становится более сложным (и не работает с bash (или со старыми версиями ksh)):

#!/bin/ksh
rm -f english.out
rm -f french.out
output=unknown
while read linein
do
    if [[ $linein == {15}(\d)\;HDR* || $linein == {15}(\d)\;TRL* ]]
    then
        output=both
    else
        if [[ $linein == {15}(\d)\;+([A-Z])\;+([^\;])\;+([^\;])\;+([^\;])\;* ]]
        then
            case ${.sh.match[5]} in
                English)
                    output=english
                ;;
                French)
                    output=french
                ;;
                *)
                    echo "unknown language: ${.sh.match[5]}" >&2
                    output=both
                ;;
            esac
        fi
    fi
    case $output in
        both)
            echo "$linein" >> english.out
            echo "$linein" >> french.out
        ;;
        english)
            echo "$linein" >> english.out
        ;;
        french)
            echo "$linein" >> french.out
        ;;
        *)
        echo "Unknown output: $output" >&2
        ;;
    esac
done < data.txt

${.sh.match[5]} содержит подвыражение # 5 в строке соответствия (части внутри скобки ()).

Вытянуть подвыражения с помощью awk проще, но это чистое ksh решение.

0 голосов
/ 31 октября 2018

Для этой задачи вам необходимо реализовать разрешение состояния. Я не думаю, что ksh только как жизненно важное решение.

awk решение на случай, если:

$ awk '
/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9];HDR/ { enfile=enfile $0 RS; frfile=frfile $0 RS; }
/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9];NFD.*;English/ { enflag=1; frflag=0; enfile=enfile $0 RS; }
/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9];NFD.*;French/ { enflag=0; frflag=1; frfile=frfile $0 RS; }
/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9];IV/ { if ( enflag==1 ) enfile=enfile $0 RS; if ( frflag==1 ) frfile=frfile $0 RS; }
/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9];TRL/ { enfile=enfile $0; frfile=frfile $0; }
END { print(enfile) > "en.txt"; print(frfile) > "fr.txt"; }
' en_fr.txt

$ cat en.txt
000000000000000;HDR;1;...
000000008651776;NFD;Individual;...;English;...
000000008651776;IV;....
000000008657876;NFD;Individual;...;English;...
999999999999999;TRL;...

$ cat fr.txt
000000000000000;HDR;1;...
000000008751796;NFD;Individual;...;French;...
000000008751796;IV;...
999999999999999;TRL;...

Примечание: я не использую стиль регулярных выражений: /^[0-9]{15}/, чтобы иметь собственную совместимость с awk, если вы работаете в UNIX.

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