Supondo que o diretório atual contenha todos os arquivos CSV e que todos tenham um .csvsufixo de nome de arquivo:
for file in ./*.csv; do
head -n 200 "$file" >"$file.200"
done
Isso gera as primeiras 200 linhas de cada arquivo CSV para um novo arquivo usando heade um redirecionamento. O nome do novo arquivo é o mesmo do antigo, mas .200anexado ao final do nome. Não há verificação para ver se o novo nome de arquivo já existe ou não.
Se pretender substituir os originais:
for file in ./*.csv; do
head -n 200 "$file" >"$file.200" &&
mv "$file.200" "$file"
done
O &&no final do headcomando faz com que mvnão seja executado se houver algum problema com a execução do head.
Se seus arquivos CSV estiverem espalhados em subdiretórios no diretório atual, use shopt -s globstare substitua o padrão ./*.csvno loop por ./**/*.csv. Isso localizará qualquer arquivo CSV dentro ou abaixo do diretório atual e executará a operação em cada um. O **padrão globbing corresponde "recursivamente" em subdiretórios, mas somente se a globstaropção shell estiver definida.
Para arquivos CSV contendo dados com novas linhas incorporadas, o acima não funcionará corretamente, pois você pode truncar um registro. Em vez disso, você teria que usar alguma ferramenta compatível com CSV para fazer o trabalho para você.
O seguinte usa CSVkit, um conjunto de ferramentas de linha de comando para análise e trabalho geral com arquivos CSV, juntamente com jq, uma ferramenta para trabalhar com arquivos JSON.
Não há ferramenta no kit CSV que possa truncar um arquivo CSV em um ponto específico, mas podemos converter os arquivos CSV em JSON e usar jqpara gerar apenas os primeiros 200 registros:
for file in ./*.csv; do
csvjson -H "$file" | jq -r '.[:200][] | map(values) | @csv' >"$file.200" &&
mv "$file.200" "$file"
done
Dado algum arquivo CSV como o exemplo abaixo,
a,b,c
1,2,3
"hello, world",2 3,4
"hello
there","my good
man",nice weather for ducks
A jqferramenta então pegaria isso e, para cada objeto na matriz (restrito aos primeiros 200 objetos), extrairia os valores como uma matriz e formataria como CSV.
Provavelmente é possível fazer essa transformação diretamente com csvpy, outra ferramenta no CSVkit, mas como minhas habilidades em Python são inexistentes, não tentarei encontrar uma solução que faça isso.
As respostas anteriores copiam dados e substituem arquivos. Esta técnica deve manter os mesmos inodes, não copiar e rodar muito mais rápido. Para cada arquivo:
(a) Encontre o comprimento de cada arquivo lendo as primeiras 200 linhas.
(b) Trunque o arquivo para esse tamanho usando truncateGNU coreutils, ou com o truncateencontrado em alguns sistemas BSD:
printf '%s\n' *.csv | parallel -- sed -ni '1,200p' {}
Isso encontrará todos os .csvarquivos no diretório atual e os alimentará no GNU paralelo, que executará um comando sed neles para manter apenas as primeiras 200 linhas. Observe que isso substituirá os arquivos no local.
Com ksh93 e uma implementação compatível com POSIX head(uma que deixa o cursor dentro de stdin logo após a última linha de saída), você pode fazer:
for file in ~(N)./*; do
[ -f "$file" ] || continue # skip non-regular files
head -n 200 0<>; "$file" > /dev/null
done
O <>;operador de redirecionamento é uma variante do <>operador padrão que trunca o arquivo no local após o retorno do comando redirecionado, desde que o comando retorne com um status de saída bem-sucedido.
Aqui, descartamos heada saída de , estamos interessados apenas em sua capacidade de deixar o cursor logo após a 200ª linha.
Infelizmente, o built-in do ksh93 head(que é ativado se você emitir builtin headou se /opt/ast/binestiver à frente de qualquer diretório com um headcomando nele $PATH) não se comporta POSIXly nesta instância. Ele lê a entrada em pedaços (como a maioria das outras headimplementações), mas não se preocupa em voltar ao final da 200ª linha quando invocado dessa maneira . Para forçá-lo a fazer essa busca de volta, precisamos executar um comando externo que anule o propósito de ter um built- headin em primeiro lugar:
builtin head # enable ksh93's head builtin
{ head -n 200 && /bin/true; } 0<>; file > /dev/null
Outra abordagem de trabalho que não envolve invocar um utilitário externo seria fazer uma busca explícita de deslocamento 0 após headretornos:
builtin head # enable ksh93's head builtin
for file in ~(N)./*; do
[ -f "$file" ] || continue # skip non-regular files
{ head -n 200 && exec <#((CUR)); } 0<>; "$file" > /dev/null
done
Para entrada CSV especificamente e para reter os primeiros 200 registros CSV (em oposição às linhas, pois um registro CSV pode conter mais de uma linha (incorporada em "..."campos entre aspas), você pode usar ksh93's read -Sespecialmente projetados para ler CSVs em um loop:
for file in ~(N)./*.csv; do
[ -f "$file" ] || continue # skip non-regular files
for ((i=0;i<200;i++)); do
IFS=, read -rSA discard
done 0<>; "$file"
done
Eu sou relativamente novo, então, por favor, seja gentil. Gostaria de receber feedback construtivo se a solução que estou propondo não for a ideal.
Eu criei 4 arquivos de amostra numerados de 1 a 4, por exemplo touch {1..4}, e cada arquivo contém 10 linhas de amostra, como no primeiro arquivo e linhas de 11 a 20 no próximo arquivo, assim por diante.
Arquivo 1
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
Arquivo 2
Line 11
Line 12
Line 13
Line 14
Line 15
Line 16
Line 17
Line 18
Line 19
Line 20
Para extrair as 2 primeiras linhas como exemplo (que podem ser extrapoladas para 200), o comando head -n 2 {1..4}retorna a saída;
==> 1 <==
Line 1
Line 2
==> 2 <==
Line 11
Line 12
==> 3 <==
Line 21
Line 22
==> 4 <==
Line 31
Line 32
O comando pode redirecionar a saída para outro arquivo com o comandohead -n 2 {1..4} > ExtractedOutput
for f in *.csv; do
printf '201,$d\nwq\n' | ed "$f"
done
Se você quiser salvar um backup, pode ser mais fácil usá -lo ex. (Você também pode considerar exmais simples de usar, independentemente; basta soltar o w!%.bak|para pular a criação de um backup primeiro.)
for f in *.csv; do
ex -c 'w!%.bak|201,$d|wq' "$f"
done
Supondo que o diretório atual contenha todos os arquivos CSV e que todos tenham um
.csv
sufixo de nome de arquivo:Isso gera as primeiras 200 linhas de cada arquivo CSV para um novo arquivo usando
head
e um redirecionamento. O nome do novo arquivo é o mesmo do antigo, mas.200
anexado ao final do nome. Não há verificação para ver se o novo nome de arquivo já existe ou não.Se pretender substituir os originais:
O
&&
no final dohead
comando faz com quemv
não seja executado se houver algum problema com a execução dohead
.Se seus arquivos CSV estiverem espalhados em subdiretórios no diretório atual, use
shopt -s globstar
e substitua o padrão./*.csv
no loop por./**/*.csv
. Isso localizará qualquer arquivo CSV dentro ou abaixo do diretório atual e executará a operação em cada um. O**
padrão globbing corresponde "recursivamente" em subdiretórios, mas somente se aglobstar
opção shell estiver definida.Para arquivos CSV contendo dados com novas linhas incorporadas, o acima não funcionará corretamente, pois você pode truncar um registro. Em vez disso, você teria que usar alguma ferramenta compatível com CSV para fazer o trabalho para você.
O seguinte usa CSVkit, um conjunto de ferramentas de linha de comando para análise e trabalho geral com arquivos CSV, juntamente com
jq
, uma ferramenta para trabalhar com arquivos JSON.Não há ferramenta no kit CSV que possa truncar um arquivo CSV em um ponto específico, mas podemos converter os arquivos CSV em JSON e usar
jq
para gerar apenas os primeiros 200 registros:Dado algum arquivo CSV como o exemplo abaixo,
o
csvjson
comando produziriaA
jq
ferramenta então pegaria isso e, para cada objeto na matriz (restrito aos primeiros 200 objetos), extrairia os valores como uma matriz e formataria como CSV.Provavelmente é possível fazer essa transformação diretamente com
csvpy
, outra ferramenta no CSVkit, mas como minhas habilidades em Python são inexistentes, não tentarei encontrar uma solução que faça isso.As respostas anteriores copiam dados e substituem arquivos. Esta técnica deve manter os mesmos inodes, não copiar e rodar muito mais rápido. Para cada arquivo:
(a) Encontre o comprimento de cada arquivo lendo as primeiras 200 linhas.
(b) Trunque o arquivo para esse tamanho usando
truncate
GNU coreutils, ou com otruncate
encontrado em alguns sistemas BSD:Usando sed com shell globbing:
Usando globbing/sed/paralelo:
Isso encontrará todos os
.csv
arquivos no diretório atual e os alimentará no GNU paralelo, que executará um comando sed neles para manter apenas as primeiras 200 linhas. Observe que isso substituirá os arquivos no local.Ou usando cabeça com paralelo:
Isso criará novos arquivos com o
.out
sufixo.Com ksh93 e uma implementação compatível com POSIX
head
(uma que deixa o cursor dentro de stdin logo após a última linha de saída), você pode fazer:O
<>;
operador de redirecionamento é uma variante do<>
operador padrão que trunca o arquivo no local após o retorno do comando redirecionado, desde que o comando retorne com um status de saída bem-sucedido.Aqui, descartamos
head
a saída de , estamos interessados apenas em sua capacidade de deixar o cursor logo após a 200ª linha.Infelizmente, o built-in do ksh93
head
(que é ativado se você emitirbuiltin head
ou se/opt/ast/bin
estiver à frente de qualquer diretório com umhead
comando nele$PATH
) não se comporta POSIXly nesta instância. Ele lê a entrada em pedaços (como a maioria das outrashead
implementações), mas não se preocupa em voltar ao final da 200ª linha quando invocado dessa maneira . Para forçá-lo a fazer essa busca de volta, precisamos executar um comando externo que anule o propósito de ter um built-head
in em primeiro lugar:Outra abordagem de trabalho que não envolve invocar um utilitário externo seria fazer uma busca explícita de deslocamento 0 após
head
retornos:Para entrada CSV especificamente e para reter os primeiros 200 registros CSV (em oposição às linhas, pois um registro CSV pode conter mais de uma linha (incorporada em
"..."
campos entre aspas), você pode usarksh93
'sread -S
especialmente projetados para ler CSVs em um loop:Eu sou relativamente novo, então, por favor, seja gentil. Gostaria de receber feedback construtivo se a solução que estou propondo não for a ideal.
Eu criei 4 arquivos de amostra numerados de 1 a 4, por exemplo
touch {1..4}
, e cada arquivo contém 10 linhas de amostra, como no primeiro arquivo e linhas de 11 a 20 no próximo arquivo, assim por diante.Arquivo 1
Arquivo 2
Para extrair as 2 primeiras linhas como exemplo (que podem ser extrapoladas para 200), o comando
head -n 2 {1..4}
retorna a saída;O comando pode redirecionar a saída para outro arquivo com o comando
head -n 2 {1..4} > ExtractedOutput
Use
ed
para truncar cada arquivo.Se você quiser salvar um backup, pode ser mais fácil usá -lo
ex
. (Você também pode considerarex
mais simples de usar, independentemente; basta soltar ow!%.bak|
para pular a criação de um backup primeiro.)