如何连接可变数量的 csv,删除它们的标题行?

如何连接可变数量的 csv,删除它们的标题行?

我有一个目录,其中包含数百个 csv 文件,其文件名以两位数字开头{01..84}。几百>> 84,所以显然有些文件名以相同的前缀开头。我希望连接文件名以相同前缀开头的文件。这是我所得到的:

#!/bin/bash
for i in {01..84}; do
        #declare array to store files with same prefix
        declare -a files=()
        echo "Processing $i"
        for j in `ls $i*.csv`; do
                #add files with same prefix to array
                files=("${files[@]}" "$j")
        done    
        #cat first file including header with the rest of the files without the headers 
        cat < ${files[@]:0:1} <(tail -n+2 ${files[@]:1}) > "$i".csv
done 

$i到目前为止一切都很好......只是,它在=22中途停止(可重复错误),并用空行和标题污染输出文件,如“==> 19XXX.csv <==”(不带引号) 。

  1. 我应该在代码中进行哪些更改才能为每个前缀获取一个漂亮的干净 csv 文件而不会使脚本崩溃?

  2. 是否有任何预编译的 bash 实用程序可供我调用来更快、更轻松地完成这些操作?

答案1

#!/bin/bash
for i in {01..84}; do
    x=$(printf '%02d' $i)
    set -- $x?*.csv
    if [ -f "$1" ]; then
        cp "$1" $i.csv
        shift
        if [ -f "$1" ]; then
            tail -q -n +2 "$@" >> $x.csv
        fi
    fi
done

对于每个前缀,它设置具有该前缀的文件列表作为参数,以便您可以用来$1访问第一个等。

如果$1是一个文件(以捕获不存在具有给定前缀的文件的情况),则将该文件复制到 prefix.csv。然后通过移出第一个文件并检查下一个文件是否也是一个文件来检查是否存在多个具有该前缀的文件。如果是这样,请通过命令跳过每个文件的标题行tail并将其附加到 prefix.csv。

如果在参数列表上传递了多个文件,则将添加抑制标题行本身-qtail选项;tail这就是你的==> 19XXX.csv <==台词的来源。

您的解决方案中可能只-q需要该选项,但我发现它过于复杂,需要bash缓冲命令等的输出,tail这可能是脚本过早停止(崩溃?)的原因。

编辑:添加x=$(printf '%02d' $i){01..84}扩展为 1 2 3 ... 没有前导零。

答案2

#!/bin/sh
for i in {01..84}
do
  cat $i*.csv > $i.csv-concat
  rm $i*.csv
  mv $i.csv-concat $i.csv
done

不要忘记cat,它是一个串联工具,tail也可以完成这项工作并删除header。

#!/bin/sh
pushd [workdir]
for i in {01..84}
do
  echo $i*.csv | xargs -n 1 tail -n+2 > $i.csv-concat
  rm $i*.csv
  mv $i.csv-concat $i.csv
done
popd

答案3

适合任何刚刚来这里复制粘贴基于 wurtel 的人的工作代码解决方案:

#!/bin/bash
for i in {01..84}; do
    #declare array to store files with same prefix
    declare -a files=()
    echo "Processing $i"
    for j in `ls $i*.csv`; do
        #add files with same prefix to array
        files=("${files[@]}" "$j")
    done
    #cat first file including header with the rest of the files without the headers
    if [ ${#files[@]} -gt 1 ]; then
        cat <(cat ${files[@]:0:1}) <(tail -q -n+2 ${files[@]:1}) > "$i".csv
    else
        cat <(cat ${files[@]:0:1}) > "$i".csv
    fi
done

Stéphane Chazelas 使用 awk 的方式。干净多了。

#!/bin/bash
for i in {01..84}; do
        echo "processing $i"
        awk 'NR==FNR||FNR>1' $i?*.csv >> "$i".csv
done

相关内容