Bash - удаление пустых столбцов из файла .csv - PullRequest
0 голосов
/ 06 февраля 2020

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

Я написал сценарий Bash, чтобы попытаться это сделать, но столкнулся с несколькими проблемами. Вот код:

#!/bin/bash

total="$(head -n 1 Reddit-cleaner.csv | grep -o ',' | wc -l)"
i=1
count=0
while [ $i -le $total ]; do
        cat Reddit-cleaner.csv | cut -d "," -f$i | while read CMD; do if [ -n CMD ]; then count=$count+1; fi; done
        if [ $count -eq 1 ]; then
                cut -d "," -f$i --complement <Reddit-cleaner.csv >Reddit-cleanerer.csv
        fi
        count=0
        i=$i+1
done

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

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

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

Редактировать: Люди спрашивали образец ввода и вывод.

Sample input:
User, Date, Email, Administrator, Posts, Comments
a, 20201719, a@a.com, Yes, , 3
b, 20182817, b@b.com, No, , 4
c, 20191618, , No, , 4
d, 20190126, , No, , 2

Sample output:
User, Data, Email, Administrator, Comments
a, 20201719, a@a.com, Yes, 3
b, 20182817, b@b.com, No, 4
c, 20191618, , No, 4
d, 20190126, , No, 2

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

Ответы [ 4 ]

1 голос
/ 06 февраля 2020

На самом деле это работа синтаксического анализатора CSV, но вы можете использовать этот скрипт awk, чтобы выполнить работу:

cat removeEmptyCellsCsv.awk

BEGIN {
   FS = OFS = ", "
}
NR == 1 {
   for (i=1; i<=NF; i++)
      e[i] = 1  # initially all cols are marked empty
   next
}
FNR == NR {
   for (i=1; i<=NF; i++)
      e[i] = e[i] && ($i == "")
   next
}
{
   s = ""
   for (i=1; i<=NF; i++)
      s = s (i==1 || e[i-1] ? "" : OFS) (e[i] ? "" : $i)
   print s
}

Затем запустите его как:

awk -f removeEmptyCellsCsv.awk file.csv{,}

Использование Приведенные в качестве примера данные, приведенные в вопросе, приведут к следующему выводу:

1, User, Date, Email, Administrator, Comments
2, a, 20201719, a@a.com, Yes, 3
3, b, 20182817, b@b.com, No, 4
4, c, 20191618, , No, 4
5, d, 20190126, , No, 2

Обратите внимание, что столбцы Posts удалены, поскольку в каждой записи они пусты.

1 голос
/ 06 февраля 2020
$ cat tst.awk
BEGIN { FS=OFS="," }
NR==FNR {
    if ( NR > 1 ) {
        for (i=1; i<=NF; i++) {
            if ( $i ~ /[^[:space:]]/ ) {
                gotValues[i]
            }
        }
    }
    next
}
{
    c=0
    for (i=1; i<=NF; i++) {
        if (i in gotValues) {
            printf "%s%s", (c++ ? OFS : ""), $i
        }
    }
    print ""
}

$ awk -f tst.awk file file
User, Date, Email, Administrator, Comments
a, 20201719, a@a.com, Yes, 3
b, 20182817, b@b.com, No, 4
c, 20191618, , No, 4
d, 20190126, , No, 2

См. Также Какой самый надежный способ эффективного анализа CSV с использованием awk? , если вам нужно работать с более сложными CSV, чем тот, который задан в вашем вопросе.

1 голос
/ 06 февраля 2020

Я могу неправильно истолковать вопрос (из-за отсутствия примера ввода и ожидаемого результата), но это должно быть так просто:

$ x="1,2,3,,4,field 5,,,six,7"
$ echo "${x//,+(,)/,}"
1,2,3,4,field 5,six,7

Для этого требуется bash с включенным extglob. В противном случае вы можете использовать внешний вызов sed:

$ echo "1,2,3,,4,field 5,,,six,7" |sed 's/,,,*/,/g'
1,2,3,4,field 5,six,7

В вашем примере кода много избыточности. Вы действительно должны учитывать awk, так как он уже отслеживает текущее количество полей (как NF) и количество строк (как NR), так что вы можете добавить это с простым total+=NF в каждой строке. Когда пустые поля свернуты, awk можно просто запустить на нужном номере поля.

$ echo "1,2,3,,4,field 5,,,six,7" |awk -F ',+' '
  { printf "line %d has %d fields, the 6th of which is <%s>\n", NR, NF, $6 }'
line 1 has 7 fields, the 6th of which is <six>

При этом используется printf для обозначения количества записей (NR, текущий номер строки), количество полей (NF) и значение шестого поля ($6) также могут быть переменными, например, $NF - это значение конечного поля, поскольку awk - это одно- индексированный).

0 голосов
/ 09 февраля 2020

Вы можете использовать Миллера (https://github.com/johnkerl/miller) и его remove-empty-columns глагол.

Начиная с

+------+----------+---------+---------------+-------+----------+
| User | Date     | Email   | Administrator | Posts | Comments |
+------+----------+---------+---------------+-------+----------+
| a    | 20201719 | a@a.com | Yes           | -     | 3        |
| b    | 20182817 | b@b.com | No            | -     | 4        |
| c    | 20191618 | -       | No            | -     | 4        |
| d    | 20190126 | -       | No            | -     | 2        |
+------+----------+---------+---------------+-------+----------+

и работая

mlr --csv remove-empty-columns input.csv >output.csv

у вас будет

+------+----------+---------+---------------+----------+
| User | Date     | Email   | Administrator | Comments |
+------+----------+---------+---------------+----------+
| a    | 20201719 | a@a.com | Yes           | 3        |
| b    | 20182817 | b@b.com | No            | 4        |
| c    | 20191618 | -       | No            | 4        |
| d    | 20190126 | -       | No            | 2        |
+------+----------+---------+---------------+----------+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...