[英]Bash - Removing empty columns from .csv file
我有一個很大的 .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
首先我找到列數,並將其存儲起來。 然后當程序還沒有到達最后一列時,我會逐列循環。 嵌套的 while 循環檢查列中的每一行是否為空,如果有多個非空行,它將所有其他列寫入另一個文件。
我認識到這個腳本存在一些問題。 首先,count 修改發生在子shell 中,因此count 永遠不會在父shell 中修改。 其次,每次腳本找到空列時,我正在寫入的文件都會被覆蓋。
所以我的問題是我該如何解決這個問題。 我最初想擁有它,以便它根據計數逐列寫入新文件,但也不知道如何完成。
編輯:人們要求提供示例輸入和輸出。
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
在示例輸出中,除了標題 (Posts) 之外沒有任何數據的列已被刪除,而完全或部分填充的列仍然存在。
我可能誤解了這個問題(由於它缺少示例輸入和預期輸出),但這應該很簡單:
$ x="1,2,3,,4,field 5,,,six,7"
$ echo "${x//,+(,)/,}"
1,2,3,4,field 5,six,7
這需要啟用extglob
bash。 否則,您可以使用外部調用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
是final 字段,因為awk
是單索引的)。
它實際上是 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
列已被刪除,因為它在每條記錄中都是空的。
$ 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
另請參閱使用 awk 有效解析 CSV 的最可靠方法是什么? 如果您需要使用比問題中更復雜的 CSV 文件。
您可以使用 Miller ( 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 |
+------+----------+---------+---------------+----------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.