如何使用 bash 将所有 csv 文件的前 200 行保留在目录中?

如何使用 bash 将所有 csv 文件的前 200 行保留在目录中?

我有大约 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。

可能可以直接使用csvpyCSVkit 中的另一个工具 进行此转换,但由于我不具备 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

相关内容