sed / Awk / cut ... Как решить, какой использовать для анализа вывода Docker? - PullRequest
0 голосов
/ 23 февраля 2019

Мой вывод:

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
jenkins/jenkins     lts                 806f56c84444        8 days ago          703MB
mongo               latest              0da05d84b1fe        2 weeks ago         394MB

Я хотел бы просто вырезать только один идентификатор изображения из вывода.

Я пытался использовать cut:

docker images | cut -d " " -f1
REPOSITORY
jenkins/jenkins

-f1 просто дает мне имена репозитариев, если я использую -f3, это имеет тенденцию быть пустым.Поскольку разделитель не является одним пробелом, я не вижу, как получить желаемый результат.

Можем ли мы cut на основе имен полей?

Я прочитал документацию и не увиделчто-нибудь актуальное.Я также увидел, что есть способ добиться этого с помощью sed / AWK, который я до сих пор выясняю.

Между тем, есть ли более простой способ добиться этого с помощью команды cut?

Я новичок в Unix / Linux, как я могу определить, какой из Sed / AWK / Cutпредпочитать?

Ответы [ 7 ]

0 голосов
/ 23 февраля 2019

В общем случае избегайте анализа выходных данных, предназначенных для потребления человеком.Многие современные утилиты предлагают возможность производить вывод в некотором стандартном формате, таком как JSON или XML, или даже CSV (хотя это менее строго определено и существует в нескольких «диалектах»).

docker, в частности, имеетобобщенная опция --format , которая позволяет указать собственный формат вывода:

docker images --format "{{.ID}}"

Если вы не можете избежать написания своего собственного анализатора (действительно ли вы уверены !? Посмотрите еще раз!), cut подходит для вывода с определенным одиночным символьным разделителем или иным образом достаточно регулярным выводом.Для всего остального я бы пошел с Awk.Из коробки он анализирует столбцы из последовательностей пробелов , поэтому он выполняет именно то, что вы конкретно просите:

docker images | awk 'NR>1 { print $3 }'

(NR>1 пропускает первую строку, содержащуюзаголовки столбцов.)

В случае столбцов фиксированной ширины он позволяет вытащить строку по индексу:

docker images | awk 'NR>1 { print substr($0, 41, 12) }'

... хотя вы можете сделать это с помощью cut тоже:

docker images | cut -c41-53

... но обратите внимание, что Docker может регулировать ширину столбцов в зависимости от размера вашего экрана!

Awk позволяет вам также писать извлечения из регулярных выражений:

awk 'NR>1 { sub(/^([^[:space:]]*[[:space:]]+){2}/, ""); sub(/[[:space]].*/, ""); print }'

Здесь он перекрывается с sed:

sed -n '2,$s/^[^ ]\+[ ]\+[^ ]\+[ ]\+\([^ ]\+\)[ ].*/\1/p'

, хотя sed значительно менее удобочитаем, особенно для нетривиальных сценариев.(Это все еще довольно тривиально.)

Если вы раньше не использовали регулярные выражения, приведенное выше будет казаться загадочным, но на самом деле его не так уж сложно выделить.Мы ищем последовательности непробелов (поле в столбце), за которыми следуют последовательности пробелов (разделитель столбцов) - две перед полем идентификатора и все, что идет после него, начиная с первого пробела после столбца идентификатора.

Если вы хотите изучить сценарии оболочки, вам, вероятно, следует также изучить хотя бы основы Awk (и мимолетное знакомство с sed).Если вы просто хотите выполнить свою работу и, возможно, не особенно заинтересованы в изучении инструментов U * x (хотя, вероятно, вам все равно это нужно!), Возможно, вместо этого изучите современный язык сценариев, такой как Python или Ruby.

... Вот библиотека Python docker :

import docker
client = docker.from_env()
for image in client.images.list():
    print(image.id)
0 голосов
/ 23 февраля 2019

Можем ли мы cut на основе имен полей ?Нет.

Как определить, какой из Sed / AWK / Cut предпочтительнее ?YMMV.Для этого конкретного ввода, где поля разделены двумя или более пробелами, с помощью awk вы можете установить разделитель полей на " +" (два или более пробелов), найти нужное имя поля (IMAGE ID ниже) и вывести только это конкретное поле:

$ awk -F"  +" '                     # set field separator
{
    if(f=="")                       # while we have not determined the desired field
        for(i=1;i<=NF;i++)          # ... keep looking
            if($i=="IMAGE ID")
                f=i
    if(f!="")                       # once found
        print $f                    # start printing it
}' file

Выход:

IMAGE ID
806f56c84444
0da05d84b1fe

В качестве однострочного:

$ awk -F"  +" '{if(f=="")for(i=1;i<=NF;i++)if($i=="IMAGE ID")f=i;if(f!="")print $f}' file
0 голосов
/ 23 февраля 2019

С Procedural Text Edit это:

forEach line {
    if (contains ci "REPOSITORY") { remove }
    keepRange word 2 1
}
removeEmptyLines // <- optional
0 голосов
/ 23 февраля 2019

Вы должны "сжать" пробел в выводе по умолчанию в один пробел.

1 2 == 1-space-space-2 == Поле 1 перед первым пробелом, Поле между первым и вторым пробелом, Поле3 после 2-го пробела.

cut -d' ' -f1 ==> '1'

cut -d' ' -f2 ==> '' пустое поле между 1 и 2 разделителем

cut -d' ' -f3==> '2'

Итак, в вашем случае используйте sed для замены последовательных пробелов на 1:

docker images | sed 's/ */ /g' | cut -d " " -f1,3

Если выходные данные имеют фиксированную ширину столбцов, тогда вы можете использовать этот вариант обрезки:

docker images | cut -c1-20,41-60

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

Если когда-либодля вывода используется TAB для заполнения, вы должны использовать expand -t n, чтобы сделать вывод последовательно заполненным пробелом, а затем применить соответствующий cut -cx,y, например (числа могут нуждаться в корректировке):

docker images | expand -t 4 | cut -c1-20,41-60

0 голосов
/ 23 февраля 2019

Ваш ввод имеет фиксированную ширину 20 символов для каждого поля, поэтому вы можете использовать функцию gawk FIELDWIDTHS.

$ awk -v FIELDWIDTHS="20 20 20 20 20" '{ print $3 }' file
IMAGE ID
806f56c84444
0da05d84b1fe
$
$ awk -v FIELDWIDTHS="20 20 20 20 20" '{ printf "%20s%20s\n", $1, $3 }' file
REPOSITORY          IMAGE ID
jenkins/jenkins     806f56c84444
mongo               0da05d84b1fe

С man gawk:

Если для переменной FIELDWIDTHS задан список чисел, разделенных пробелами, ожидается, что каждое поле будет иметь фиксированную ширину, и gawk разделяет запись, используя заданную ширину.Каждой ширине поля может дополнительно предшествовать разделенное двоеточиями значение, указывающее количество символов, которые следует пропустить перед началом поля.Значение FS игнорируется.Присвоение нового значения FS или FPAT отменяет использование FIELDWIDTHS.

0 голосов
/ 23 февраля 2019

Не могли бы вы попробовать следующее, это должно работать, если в вашем поле TAG есть пробелы и нам НЕ нужно жестко кодировать какие-либо номера полей здесь.Я предположил, что строка ago всегда будет на выходе (какой AFAIK должен быть на выходе докера).

your_command | awk '{gsub(/ago.*/,"");NF-=2} 1'

Пример вывода будет следующим:

REPOSITORY TAG IMAGE ID
jenkins/jenkins lts 806f56c84444
mongo latest 0da05d84b1fe

Или весли ваш awk не поддерживает NF-=2, попробуйте следующее.

your_command | awk '{gsub(/ago.*/,"");$(NF-1)=$NF="";sub(/[[:space:]]+$/,"")} 1'
0 голосов
/ 23 февраля 2019

Попробуйте:

docker images | tr -s ' ' | cut -f3 -d' '

Команда tr -s ' ' преобразует несколько пробелов в один, а после с помощью cut вы можете захватить ваше поле.Это хорошо работает, если значения в вашем поле не имеют пробелов.

...