как узнать общие столбцы и их записи из двух файлов с помощью awk - PullRequest
0 голосов
/ 16 мая 2018

У меня есть два файла:

Файл 1:

id|name|address|country
1|abc|efg|xyz
2|asd|dfg|uio

Файл 2 (только заголовки):

id|name|country

Теперь я хочу вывод:

OUTPUT:

id|name|country
1|abc|xyz
2|asd|uio

По сути, у меня есть файл записей пользователя (file1) и файл заголовка (file2). Теперь я хочу извлечь только те записи из (file1), чьистолбцы соответствуют этому в заголовочном файле.

Я хочу сделать это с помощью awk или bash.

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

awk 'BEGIN { OFS="..."} FNR==NR { a[(FNR"")] = $0; next } { print a[(FNR"")], $0 > "test.txt"}' header.txt file.txt

и понятия не имею, что делать дальше.

Спасибо

Ответы [ 5 ]

0 голосов
/ 16 мая 2018

с (много) трубами Unix как Даг Макилрой предназначен ...

$ function p() { sed 1q "$1" | tr '|' '\n' | cat -n | sort -k2; }
$ cut -d'|' -f"$(join -j2 <(p header) <(p file) | sort -k2n | cut -d' ' -f3 | paste -sd,)" file

id|name|country
1|abc|xyz
2|asd|uio
0 голосов
/ 16 мая 2018

Этот учитывает порядок столбцов в file1, изменил порядок:

$ cat file1
id|country|name

The awk:

$ awk '
BEGIN { FS=OFS="|" }
NR==1 {                                             # file1
    n=split($0,a)
    next
}
NR==2 {                                             # file2 header
    for(i=1;i<=NF;i++)
        b[$i]=i
} 
{                                                   # output part
    for(i=1;i<=n;i++)
        printf "%s%s", $b[a[i]], (i==n?ORS:OFS)
}' file1 file2
id|country|name
1|xyz|abc
2|uio|asd

(Другая версия, использующая cut для вывода в редакциях )

0 голосов
/ 16 мая 2018

Решение с использованием bash> 4:

IFS='|' headers1=($(head -n1 $file1))
IFS='|' headers2=($(head -n1 $file2))
IFS=$'\n'


# find idxes we want to output, ie. mapping of headers1 to headers2
idx=()
for i in $(seq 0 $((${#headers2[@]}-1))); do
        for j in $(seq 0 $((${#headers1[@]}-1))); do
                if [ "${headers2[$i]}" == "${headers1[$j]}" ]; then
                        idx+=($j)
                        break
                fi
        done
done
# idx=(0 1 3) for example

# simple join output function from /1079371/kak-ya-mogu-obedinit-elementy-massiva-v-bash
join_by() { local IFS="$1"; shift; echo "$*"; }

# first line - output headers
join_by '|' "${headers2[@]}"

isfirst=true
while IFS='|' read -a vals; do
        # ignore first (header line)
        if $isfirst; then
                isfirst=false
                continue;
        fi;
        # filter from line only columns with idx indices
        tmp=()
        for i in ${idx[@]}; do 
             tmp+=("${vals[$i]}")
        done
        # join ouptut with '|'
        join_by '|' "${tmp[@]}"
done < $file1
0 голосов
/ 16 мая 2018

Это похоже на решение RavinderSingh13 в том, что оно сначала считывает заголовки из более короткого файла, а затем решает, какие столбцы сохранить из более длинного файла, основываясь на заголовках в первой строке.

Однако вывод по-разному.Вместо создания строки она сдвигает столбцы влево, если не хочет включать определенное поле.

BEGIN       { FS = OFS = "|" }

# read headers from first file
NR == FNR   { for (i = 1; i <= NF; ++i) header[$i]; next }

# mark fields in second file as "selected" if the header corresponds
# to a header in the first file
FNR == 1    {
    for (i = 1; i <= NF; ++i)
        select[i] = ($i in header)
}

{
    skip = 0
    pos  = 1
    for (i = 1; i <= NF; ++i)
        if (!select[i]) {          # we don't want this field
            ++skip
            $pos = $(pos + skip)   # shift fields left
        } else
            ++pos

    NF -= skip  # adjust number of fields
    print
}

Выполнение этого:

$ mawk -f script.awk file2 file1
id|name|country
1|abc|xyz
2|asd|uio
0 голосов
/ 16 мая 2018

После awk может помочь вам в том же.

awk -F"|" 'FNR==NR{for(i=1;i<=NF;i++){a[$i]};next} FNR==1 && FNR!=NR{for(j=1;j<=NF;j++){if($j in a){b[++p]=j}}} {for(o=1;o<=p;o++){printf("%s%s",$b[o],o==p?ORS:OFS)}}' OFS="|" File2  File1

Теперь добавляем не-лайнерную форму решения.

awk -F"|" '
FNR==NR{
   for(i=1;i<=NF;i++){
     a[$i]};
   next}
FNR==1 && FNR!=NR{
   for(j=1;j<=NF;j++){
     if($j in a){ b[++p]=j }}
}
{
   for(o=1;o<=p;o++){
     printf("%s%s",$b[o],o==p?ORS:OFS)}
}
' OFS="|" File2  File1

Редактирование Эд Мортон: FWIW вот тот же сценарий, написанный с нормальным отступом / интервалом и парой более значимых имен переменных:

BEGIN { FS=OFS="|" }
NR==FNR {
    for (i=1; i<=NF; i++) {
        names[$i]
    }
    next
}
FNR==1 {
    for (i=1; i<=NF; i++) {
        if ($i in names) {
            f[++numFlds] = i
        }
    }
}
{
    for (i=1; i<=numFlds; i++) {
        printf "%s%s", $(f[i]), (i<numFlds ? OFS : ORS)
    }
}
...