我有大约 50 个非常大的 csv 文件,它们有数千行。
我只想保留每个文件的前 200 行 - 如果生成的文件覆盖原始文件,我没问题。
我应该使用什么命令来执行此操作?
答案1
假设当前目录包含所有 CSV 文件,并且它们都有一个.csv
文件名后缀:
for file in ./*.csv; do
head -n 200 "$file" >"$file.200"
done
head
这将使用重定向将每个 CSV 文件的前 200 行输出到新文件。新文件的名称与旧文件的名称相同,但附加.200
在名称末尾。不会检查新文件名是否已存在。
如果你想更换原来的:
for file in ./*.csv; do
head -n 200 "$file" >"$file.200" &&
mv "$file.200" "$file"
done
命令末尾&&
的head
使得mv
如果运行出现问题,就不会运行head
。
如果您的 CSV 文件分散在当前目录下的子目录中,则使用然后将循环中的shopt -s globstar
模式替换为.这将找到当前目录中或当前目录下的任何 CSV 文件,并对每个文件执行操作。通配模式会“递归地”匹配子目录,但前提是设置了 shell 选项。./*.csv
./**/*.csv
**
globstar
对于包含嵌入换行符的数据的 CSV 文件,上述方法将无法正常工作,因为您可能会截断记录。相反,您必须使用一些支持 CSV 的工具来为您完成这项工作。
下面使用 CSVkit(一组用于解析和一般处理 CSV 文件的命令行工具)以及jq
一个用于处理 JSON 文件的工具。
CSV 套件中没有可以在特定点截断 CSV 文件的工具,但我们可以将 CSV 文件转换为 JSON 并用于jq
仅输出前 200 条记录:
for file in ./*.csv; do
csvjson -H "$file" | jq -r '.[:200][] | map(values) | @csv' >"$file.200" &&
mv "$file.200" "$file"
done
给定一些 CSV 文件,如下面的简短示例,
a,b,c
1,2,3
"hello, world",2 3,4
"hello
there","my good
man",nice weather for ducks
该csvjson
命令会产生
[
{
"a": "a",
"b": "b",
"c": "c"
},
{
"a": "1",
"b": "2",
"c": "3"
},
{
"a": "hello, world",
"b": "2 3",
"c": "4"
},
{
"a": "hello\nthere",
"b": "my good\nman",
"c": "nice weather for ducks"
}
]
然后,该jq
工具将获取此数据,并针对数组中的每个对象(仅限前 200 个对象),将值提取为数组并将其格式化为 CSV。
可能可以直接使用csvpy
CSVkit 中的另一个工具 进行此转换,但由于我不具备 Python 技能,因此我不会尝试提出实现此目的的解决方案。
答案2
以前的答案复制数据并覆盖文件。这种技术应该保持相同的索引节点,不进行复制,并且运行速度要快得多。对于每个文件:
(a) 通过读取前 200 行找出每个文件的长度。
truncate
(b) 使用GNU coreutils 或truncate
某些 BSD 系统上的命令将文件截断为该长度:
SZ="$( head -n 200 -- "${file}" | wc -c )"
truncate -s "${SZ}" -- "${file}"
答案3
将 sed 与 shell 通配符结合使用:
sed -ni '1,200p' *.csv
使用 globbing/sed/parallel:
printf '%s\n' *.csv | parallel -- sed -ni '1,200p' {}
这将找到.csv
该目录下的所有文件当前目录并将它们提供给 GNU Parallel,后者将对它们执行 sed 命令以仅保留前 200 行。请注意,这将覆盖原位的文件。
或者使用平行头:
printf '%s\n' *.csv | parallel -- head -n 200 {} ">" {}.out
这将创建带有.out
后缀的新文件。
答案4
我比较新,所以请温柔一点。如果我提出的解决方案不是最佳的,我将不胜感激建设性的反馈。
我创建了 4 个示例文件,编号为 1 到 4,例如touch {1..4}
,每个文件包含 10 个示例行,例如第一个文件中的行和下一个文件中的第 11 行到 20 行,依此类推。
文件1
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
文件2
Line 11
Line 12
Line 13
Line 14
Line 15
Line 16
Line 17
Line 18
Line 19
Line 20
以提取前 2 行为例(可以推断为 200),该命令head -n 2 {1..4}
返回输出;
==> 1 <==
Line 1
Line 2
==> 2 <==
Line 11
Line 12
==> 3 <==
Line 21
Line 22
==> 4 <==
Line 31
Line 32
该命令可以使用命令将输出重定向到另一个文件head -n 2 {1..4} > ExtractedOutput