Обработка текста Точно выходной файл - proUbuntu
3 голосов
/

У меня есть текстовый файл, созданный на основе выходных данных инструмента управления хранилищем aptly, в котором перечислены мои опубликованные хранилища, из которых мне нужно извлечь информацию.

Формат файла следующий:

Published repositories:
 * test_repo_one/xenial [i386,amd64] publishes {main: [xenial-main_20190311]: Snapshot from mirror [xenial-main]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {multiverse: [xenial-multiverse_20190311]: Snapshot from mirror [xenial-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {restricted: [xenial-restricted_20190311]: Snapshot from mirror [xenial-restricted]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {universe: [xenial-universe_20190311]: Snapshot from mirror [xenial-universe]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}
 * test_repo_one/xenial-security [i386,amd64] publishes {main: [xenial-security-main_20190311]: Snapshot from mirror [xenial-security-main]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {multiverse: [xenial-security-multiverse_20190311]: Snapshot from mirror [xenial-security-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {restricted: [xenial-security-restricted_20190311]: Snapshot from mirror [xenial-security-restricted]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {universe: [xenial-security-universe_20190311]: Snapshot from mirror [xenial-security-universe]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}
 * test_repo_two/trusty [i386,amd64] publishes {main: [trusty-main_20190312]: Snapshot from mirror [trusty-main]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {multiverse: [trusty-multiverse_20190312]: Snapshot from mirror [trusty-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {restricted: [trusty-restricted_20190312]: Snapshot from mirror [trusty-restricted]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {universe: [trusty-universe_20190312]: Snapshot from mirror [trusty-universe]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}
...

Последняя строка вывода заканчивается новой строкой.

Строка "Опубликованные репозитории:" не обязательна.

Для каждой из строк, начинающихся с '*', мне нужно удалить постороннюю информацию, оставив только имена снимков. Нет способа сделать это в aptly. Желаемый вывод для первой из этих строк:

test_repo_one/xenial [xenial-main_20190311] [xenial-multiverse_20190311] [xenial-restricted_20190311] [xenial-universe_20190311]

Квадратные скобки не являются необходимыми, так что решение, которое сохраняет или удаляет их, подойдет. Я бы предпочел решение sed или awk, но все, что работает, будет высоко оценено.

Ответы [ 3 ]

2 голосов
/

Два ответа в одном

Я разместил здесь два ответа:

  • Скрипт bash, который, надеюсь, легче понять
  • Однострочник с использованием обычных утилит Linux cat, grep, sed и cut

Как выглядит скрипт Bash в действии

Я отключил перенос строки в терминале gnome, чтобы облегчить чтение входных и выходных файлов.

───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/askubuntu$ tput rmam # Turn off line wrap
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/askubuntu$ cat aptfilein
Published repositories:
 * test_repo_one/xenial [i386,amd64] publishes {main: [xenial-main_20190311]: Snapshot from mirr}
 * test_repo_one/xenial-security [i386,amd64] publishes {main: [xenial-security-main_20190311]: }
 * test_repo_two/trusty [i386,amd64] publishes {main: [trusty-main_20190312]: Snapshot from mirr}
...
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/askubuntu$ time aptfileparse.sh
5 lines read from aptfilein
3 lines written to aptfileout

real    0m0.025s
user    0m0.016s
sys     0m0.004s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/askubuntu$ cat aptfileout
 test_repo_one/xenial [xenial-main_20190311] [xenial-multiverse_20190311] [xenial-restricted_201]
 test_repo_one/xenial-security [xenial-security-main_20190311] [xenial-security-multiverse_20190]
 test_repo_two/trusty [trusty-main_20190312] [trusty-multiverse_20190312] [trusty-restricted_201]
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/askubuntu$ 

Фактический скрипт Bash

Не забудьте сделать скрипт исполняемым с chmod a+x script.sh

#!/bin/bash

# NAME: aptfileparse.sh
# PATH: ~/askubuntu
# DESC: Parse Apt File giving new lines.
# DATE: July 1, 2019.
# NOTE: For: /635634/obrabotka-teksta-tochno-vyhodnoi-fail
#       Program would be ~10 lines shorter (but harder to read) with arrays.

: <<'END'
/* -----------------------------------------------------------------------------

INPUT FILE LAYOUT
=================

Published repositories:
 * test_repo_one/xenial [i386,amd64] publishes {main: [xenial-main_20190311]: Snapshot from mirror [xenial-main]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {multiverse: [xenial-multiverse_20190311]: Snapshot from mirror [xenial-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {restricted: [xenial-restricted_20190311]: Snapshot from mirror [xenial-restricted]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {universe: [xenial-universe_20190311]: Snapshot from mirror [xenial-universe]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}
 * test_repo_one/xenial-security [i386,amd64] publishes {main: [xenial-security-main_20190311]: Snapshot from mirror [xenial-security-main]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {multiverse: [xenial-security-multiverse_20190311]: Snapshot from mirror [xenial-security-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {restricted: [xenial-security-restricted_20190311]: Snapshot from mirror [xenial-security-restricted]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {universe: [xenial-security-universe_20190311]: Snapshot from mirror [xenial-security-universe]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}
 * test_repo_two/trusty [i386,amd64] publishes {main: [trusty-main_20190312]: Snapshot from mirror [trusty-main]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {multiverse: [trusty-multiverse_20190312]: Snapshot from mirror [trusty-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {restricted: [trusty-restricted_20190312]: Snapshot from mirror [trusty-restricted]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {universe: [trusty-universe_20190312]: Snapshot from mirror [trusty-universe]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}
...

OUTPUT FILE LAYOUT
==================

 test_repo_one/xenial [xenial-main_20190311] [xenial-multiverse_20190311] [xenial-restricted_20190311] [xenial-universe_20190311]

Five fields to extract: name, main, multiverse, restricted, universe

----------------------------------------------------------------------------- */
END

 INPUT="aptfilein"
OUTPUT="aptfileout"

> "$OUTPUT" # Erase previous output file

# Read all input lines
while IFS= read -r line ; do

    let CountIn++
    ! [[ "$line" =~ " *" ]] && continue     # skip lines not starting " *"
    # Get name
    line="${line#" * "}"                    # remove leading " * "
    lout="${line%%" "*}"                    # name is up to next " "
    line="${line#" "*}"                     # remove name from line
    # Get main
    line="${line#*"{main: "}"               # remove leading "{main: "
    lout="$lout ${line%%":"*}"              # main is up to next ":"
    line="${line#":"*}"                     # remove name from line
    # Get multiverse
    line="${line#*"{multiverse: "}"         # remove leading "{multiverse: "
    lout="$lout ${line%%":"*}"              # maultiverse is up to next ":"
    line="${line#":"*}"                     # remove multiverse from line
    # Get restricted
    line="${line#*"{restricted: "}"         # remove leading "{restricted: "
    lout="$lout ${line%%":"*}"              # restricted is up to next ":"
    line="${line#":"*}"                     # remove restricted from line
    # Get universe
    line="${line#*"{universe: "}"           # remove leading "{universe: "
    lout="$lout ${line%%":"*}"              # universe is up to next ":"
    line="${line#":"*}"                     # remove universe from line

    # Append line to output file with leading space
    echo " $lout" >> "$OUTPUT"
    let CountOut++

done < "$INPUT"

echo  "$CountIn lines read from $INPUT"
echo "$CountOut lines written to $OUTPUT"

Однострочник с общими утилитами

Однострочники популярны в сообществе Linux, и в этих вопросах и ответах есть несколько превосходных ответов awk и perl. Вот пример использования общих утилит, с которыми знакомы наиболее опытные пользователи командной строки:

$ time cat aptfilein | grep ^" \*" | sed 's/ \* //;s/ /: /;s/^/ /' | cut -d':' -f1,3,6,9,12 --output-delimiter=''
 test_repo_one/xenial [xenial-main_20190311] [xenial-multiverse_20190311] [xenial-restricted_20190311] [xenial-universe_20190311]
 test_repo_one/xenial-security [xenial-security-main_20190311] [xenial-security-multiverse_20190311] [xenial-security-restricted_20190311] [xenial-security-universe_20190311]
 test_repo_two/trusty [trusty-main_20190312] [trusty-multiverse_20190312] [trusty-restricted_20190312] [trusty-universe_20190312]

real    0m0.007s
user    0m0.012s
sys     0m0.003s
  • cat aptfilein | - команда cat выводит список файлов. Команда pipe (|) передает выходные данные следующей команде.
  • grep ^" \*" - команда grep ищет строку. Морковь (^) обозначает, что строка должна начинаться с начала строки. Обратная косая черта (\) означает, что звездочка / сплат (*) должна восприниматься буквально, а не как символ подстановки, который выбирает все. Таким образом, команда grep выбирает все строки, начинающиеся с *.
  • sed - это «потоковый редактор», который редактирует входящие строки, изменяет их и пропускает. Здесь есть три sed изменения 's/ \* //;s/ /: /;s/^/ /'. Изменения происходят между кавычками (') и очерчены (разделены) разделителем точек с запятой (;). Они разбиты на следующие три пункта.
  • s/ \* // - найти первое вхождение * и изменить его на ноль. Это сотрет *, который начинается с каждой строки.
  • s/ /: / - ищет первый пробел и заменяет его на двоеточие (:), за которым следует пробел. Это необходимо, чтобы изменить наше первое поле на ключ. Например test_repo_one/xenial становится test_repo_one/xenial:.
  • s/^/ / - говорит sed вставлять пробел в начале каждой строки.
  • cut -d':' -f1,3,6,9,12 --output-delimiter='' - Использует команду cut для выбора ключевых полей # 1, 3, 6, 9 и 12. Ключевые поля обозначаются двоеточием в качестве аргумента -d':'. Обычно поля вывода разделяются одним и тем же разделителем, но он переопределяется на ноль с помощью параметра --output-delimiter = '' `.

Примечание: Однострочник быстрее, чем bash, потому что он медленнее при обработке строк.

1 голос
/

Подход Perl:

$ perl -lne 'next unless /^\s*\*\s*(\S+)/; $n=$1; @k=(/\{.+?:\s*\[(.+?)\]/g); print "$n @k"' file 
test_repo_one/xenial xenial-main_20190311 xenial-multiverse_20190311 xenial-restricted_20190311 xenial-universe_20190311
test_repo_one/xenial-security xenial-security-main_20190311 xenial-security-multiverse_20190311 xenial-security-restricted_20190311 xenial-security-universe_20190311
test_repo_two/trusty trusty-main_20190312 trusty-multiverse_20190312 trusty-restricted_20190312 trusty-universe_20190312

Объяснение

  • perl -lne: построчно читать входной файл (-n), удалять завершающие символы новой строки (-l) и запускать скрипт, заданный -e в каждой строке. -l также добавляет новую строку к каждому вызову print.
  • next unless /^\s*\*\s*(\S+)/;: найти имя репо, поэтому первый отрезок непробельных символов (\S+) в строке начинается с 0 или более пробельных символов (^\s*), затем * (\*) и снова 0 или более пробельных символов. Самое длинное пространство без пробелов после этого - то, что мы хотим. Если эта строка не соответствует этому регулярному выражению, next переместит нас на следующую строку.
  • $n=$1: сохранить то, что было захвачено совпадением выше ((\S+) в скобках, $1), как $n.
  • @k=(/\{.+?:\s*\[(.+?)\]/g): найдите все случаи, когда у нас есть {, любые другие символы, а затем :, затем пробел и [ и захватите что-нибудь между [ и ]. Сохраните все соответствующие строки в массиве @k.
  • print "$n @k": наконец, напечатайте имя репо, $n и массив @k сверху.

Если вы предпочитаете использовать квадратные скобки, вы можете использовать:

$ perl -lne 'next unless /^\s*\*\s*(\S+)/; $n=$1; @k=(/\{.+?:\s*(\[.+?\])/g); print "$n @k"' file 
test_repo_one/xenial [xenial-main_20190311] [xenial-multiverse_20190311] [xenial-restricted_20190311] [xenial-universe_20190311]
test_repo_one/xenial-security [xenial-security-main_20190311] [xenial-security-multiverse_20190311] [xenial-security-restricted_20190311] [xenial-security-universe_20190311]
test_repo_two/trusty [trusty-main_20190312] [trusty-multiverse_20190312] [trusty-restricted_20190312] [trusty-universe_20190312]
0 голосов
/

Мой подход к awk:

$ cat 1.txt 
Published repositories:
 * test_repo_one/xenial [i386,amd64] publishes {main: [xenial-main_20190311]: Snapshot from mirror [xenial-main]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {multiverse: [xenial-multiverse_20190311]: Snapshot from mirror [xenial-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {restricted: [xenial-restricted_20190311]: Snapshot from mirror [xenial-restricted]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}, {universe: [xenial-universe_20190311]: Snapshot from mirror [xenial-universe]: http//gb.archive.ubuntu.com/ubuntu/ xenial [src]}
 * test_repo_one/xenial-security [i386,amd64] publishes {main: [xenial-security-main_20190311]: Snapshot from mirror [xenial-security-main]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {multiverse: [xenial-security-multiverse_20190311]: Snapshot from mirror [xenial-security-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {restricted: [xenial-security-restricted_20190311]: Snapshot from mirror [xenial-security-restricted]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}, {universe: [xenial-security-universe_20190311]: Snapshot from mirror [xenial-security-universe]: http//gb.archive.ubuntu.com/ubuntu/ xenial-security[src]}
 * test_repo_two/trusty [i386,amd64] publishes {main: [trusty-main_20190312]: Snapshot from mirror [trusty-main]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {multiverse: [trusty-multiverse_20190312]: Snapshot from mirror [trusty-multiverse]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {restricted: [trusty-restricted_20190312]: Snapshot from mirror [trusty-restricted]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}, {universe: [trusty-universe_20190312]: Snapshot from mirror [trusty-universe]: http//gb.archive.ubuntu.com/ubuntu/ trusty[src]}

$ awk '$1=="*"{split ($0, a, /:/); print $2 a[2] a[5] a[8] a[11]}' 1.txt 
test_repo_one/xenial [xenial-main_20190311] [xenial-multiverse_20190311] [xenial-restricted_20190311] [xenial-universe_20190311]
test_repo_one/xenial-security [xenial-security-main_20190311] [xenial-security-multiverse_20190311] [xenial-security-restricted_20190311] [xenial-security-universe_20190311]
test_repo_two/trusty [trusty-main_20190312] [trusty-multiverse_20190312] [trusty-restricted_20190312] [trusty-universe_20190312]
...