Как я могу обобщить команду awk в сценарий? (извлечение/перегруппировка столбцов из файла)

Решено следующим образом:

name = 'ArkOS_Dev'
kernel = "/mnt/arch/boot/x86_64/vmlinuz"
ramdisk = "/mnt/arch/boot/x86_64/archiso.img"
extra = "archisobasedir=arch archisolabel=ARCH_201511"
memory = 2048
vcpus = 3
disk = [ "format=raw, vdev=xvda, access=rw, target=/dev/vm_volumes/root.ArkOS_Dev",
         "format=raw, vdev=xvdb, access=rw, target=/dev/vm_volumes/swap.ArkOS_Dev",
         "format=raw, vdev=xvdc, access=ro, devtype=cdrom, target=/home/xen/ISO/archlinux-2015.11.01-dual.iso"
       ]
vif = [ 'mac=00:16:3e:49:2b:a1,bridge=xenbr0' ]
root = "/dev/xvda rw"

Затем после установки DomU следующим образом:

name = 'ArkOS_Dev'
bootloader = "pygrub"
memory = 2048
vcpus = 3
disk = [ "format=raw, vdev=xvda, access=rw, target=/dev/vm_volumes/root.ArkOS_Dev",
         "format=raw, vdev=xvdb, access=rw, target=/dev/vm_volumes/swap.ArkOS_Dev"
       ]
vif = [ 'mac=00:16:3e:49:2b:a1,bridge=xenbr0' ]
root = "/dev/xvda rw"
0
23.07.2018, 13:49
3 ответа

Вы можете использовать bashgetopts(вам нужно немного прокрутить вниз )для разбора командной строки:

#!/bin/bash
delimiter=:
first=1
second=2
while getopts d:f:s: FLAG; do
  case $FLAG in
    d) delimiter=$OPTARG;;
    f) first=$OPTARG;;
    s) second=$OPTARG;;
    *) echo error >&2; exit 2;;
  esac
done
shift $((OPTIND-1))
awk -F"$delimiter" -v "OFS=$delimiter" -v first="$first" -v second="$second" '{ print $first OFS $second }' "$@"
2
28.01.2020, 02:23

Следующий сценарий оболочки использует необязательную опцию -dдля установки вкладки-разделителя (по умолчанию ), а также необязательную -необязательную опцию -cсо спецификацией столбца.

Спецификация столбца аналогична спецификации cut, но также позволяет переупорядочивать и дублировать выходные столбцы, а также указывать диапазоны в обратном порядке. Также поддерживаются открытые диапазоны.

Файл для анализа задается в командной строке как последний операнд или передается на стандартный ввод.

#!/bin/sh

delim='\t'   # tab is default delimiter

# parse command line option
while getopts 'd:c:' opt; do
    case $opt in
        d)
            delim=$OPTARG
            ;;
        c)
            cols=$OPTARG
            ;;
        *)
            echo 'Error in command line parsing' >&2
            exit 1
    esac
done
shift "$(( OPTIND - 1 ))"

if [ -z "$cols" ]; then
    echo 'Missing column specification (the -c option)' >&2
    exit 1
fi

# ${1:--} will expand to the filename or to "-" if $1 is empty or unset
cat "${1:--}" |
awk -F "$delim" -v cols="$cols" '
    BEGIN {
        # output delim will be same as input delim
        OFS = FS

        # get array of column specs
        ncolspec = split(cols, colspec, ",")
    }

    {
        # get fields of current line
        # (need this as we are rewriting $0 below)
        split($0, fields, FS)

        nf = NF     # save NF in case we have an open-ended range
        $0 = "";    # empty $0

        # go through given column specification and
        # create a record from it
        for (i = 1; i <= ncolspec; ++i)
            if (split(colspec[i], r, "-") == 1)
                # single column spec
                $(NF+1) = fields[colspec[i]]
            else {
                # column range spec

                if (r[1] == "") r[1] = 1    # open start range
                if (r[2] == "") r[2] = nf   # open end range

                if (r[1] < r[2])
                    # forward range
                    for (j = r[1]; j <= r[2]; ++j)
                        $(NF + 1) = fields[j]
                else
                    # backward range
                    for (j = r[1]; j >= r[2]; --j)
                        $(NF + 1) = fields[j]
            }

        print
    }'

В этом есть небольшая неэффективность, так как код должен повторно -анализировать спецификацию столбца для каждой новой строки. Если поддержка открытых -конечных диапазонов не требуется или если предполагается, что все строки имеют одинаковое количество столбцов, можно выполнить только один проход по спецификации в блоке BEGIN(или в блоке (. отделить NR==1блок )для создания массива полей, которые должны быть выведены.

Отсутствует :Проверка корректности спецификации столбца. Неверно сформированная строка спецификации вполне может вызвать странности.

Тестирование:

$ cat file
1:2:3
a:b:c
@:(:)
$ sh script.sh -d : -c 1,3 <file
1:3
a:c
@:)
$ sh script.sh -d : -c 3,1 <file
3:1
c:a
):@
$ sh script.sh -d : -c 3-1,1,1-3 <file
3:2:1:1:1:2:3
c:b:a:a:a:b:c
):(:@:@:@:(:)
$ sh script.sh -d : -c 1-,3 <file
1:2:3:3
a:b:c:c
@:(:):)
2
28.01.2020, 02:23

Спасибо за ответы. Вот мой сценарий. Я создал его методом проб и ошибок, который не часто приводит к рабочему решению, и у меня нет систематического способа придумать сценарий, к которому я всегда стремлюсь. Пожалуйста, предоставьте обзор кода, если можете. Спасибо.

Скрипт работает в следующих примерах (не уверен, работает ли вообще):

$ projection -d ":" /etc/passwd 4 3 6 7

$ projection -d "/" /etc/passwd 4 3 6 7

Сценарий projectionравен:

#! /bin/bash

# default arg value                                                                                                                                                               
delim="," # CSV by default                                                                                                                                                        
# Parse flagged arguments:                                                                                                                                                        
while getopts "td:" flag
do
  case $flag in
    d) delim=$OPTARG;;
    t) delim="\t";;
    ?) exit;;
  esac
done
# Delete the flagged arguments:                                                                                                                                                   
shift $(($OPTIND -1))

inputfile="$1"
shift 1

fs=("$@")
# prepend "$" to each field number                                                                                                                                                
fields=()
for f in "${fs[@]}"; do
    fields+=(\$"$f")
done

awk -F"$delim" "{ print $(join_by.sh " \"$delim\" " "${fields[@]}") }" "$inputfile"

где join_by.shэто

#! /bin/bash                                                                                                                                                                      

# https://stackoverflow.com/questions/1527049/join-elements-of-an-array                                                                                                           
# https://stackoverflow.com/a/2317171/                                                                                                                                

# get the separator:                                                                                                                                                              
d="$1";
shift;

# interpolate other parameters by teh separator                                                                                                                                   
# by treating the first parameter specially                                                                                                                                       
echo -n "$1";
shift;
printf "%s" "${@/#/$d}";
-1
28.01.2020, 02:23

Теги

Похожие вопросы