Existem muitos cenários em que você precisa analisar, modificar e processar rapidamente arquivos grandes, tanto em quantidade quanto em tamanho. Esses arquivos costumam ser CSV (Comma Separated Values) em texto puro. Abrir esse tipo de arquivo em planilhas como Excel, LibreOffice ou OpenOffice pode estourar a memória da sua máquina. Além disso, processar muitos arquivos em lote costuma falhar depois de algumas horas por conta de alguma anomalia inesperada.
Você inevitavelmente perde muito tempo com telas travadas, reinicializações e longas esperas.
Só que a maioria dessas tarefas poderia ser feita com poucas linhas de código. Mais ainda: estar familiarizado com alguns comandos simples de shell pode economizar muito tempo e reduzir a frustração.
Este post traz uma visão geral de alguns comandos de shell que eu uso praticamente todos os dias. Espero que sejam úteis para você.
Anotações rápidas
Atenção: existem diferentes tipos de shell (bash, zsh, ...). O bash é o mais comum, pois é o shell padrão no OS X e nas principais distribuições Linux. O Zsh (e o Oh My Zsh) é uma alternativa popular e poderosa. Os comandos de shell deste post foram testados no bash no OS X (macOS) e devem funcionar em outros shells e ambientes.
Todos os exemplos a seguir usam o conjunto de dados adult do repositório UCI Machine Learning, também conhecido como "Census Income", disponível aqui. Esse dataset é comumente usado para prever se a renda excede \$50K/ano com base em dados do censo. Com 48.842 linhas e 14 atributos, não é um dataset grande, mas é suficiente para ilustrar os exemplos. Embora o arquivo tenha a extensão .data, ele é um CSV bem formatado. Fique à vontade para baixar e acompanhar!
Conte com wc
Dado um novo arquivo de texto, você quer saber quantas linhas ele tem. Isso pode ser feito com o comando de contagem de palavras wc -l:
O que indica que o arquivo adult.data contém 32.562 linhas. A flag -l instrui o wc a contar linhas. Você também pode usar wc para contar palavras com a flag -w.
O arquivo adult.data contém quase 500 mil palavras.
O comando wc também pode contar quantos arquivos há em um diretório usando a saída de um simples ls -l como entrada para o wc. Usar a saída de um comando como entrada para outro com o pipe | é um padrão útil chamado pipelining. Você vai vê-lo em vários exemplos neste post.
Suponha agora que você tenha uma pasta com muitos arquivos. O comando abaixo informa exatamente quantos itens ela contém:
Há muitas outras aplicações para o wc quando você começa a usar curingas e subpastas.
Voltando ao arquivo adult.data, vamos olhar as primeiras linhas com o comando head. Por padrão, head exibe 10 linhas; você pode limitar a saída às 2 primeiras com a flag -n.
Note que o arquivo não tem linha de cabeçalho. Os nomes das colunas não estão no arquivo. Você pode adicionar essa linha de cabeçalho concatenando dois arquivos com o comando cat.
Concatene arquivos com cat
O comando cat imprime o conteúdo de um arquivo na saída padrão (ou seja, no terminal). Ele também pode concatenar uma série de arquivos. O comando cat file_1.csv file_2.csv > target_file.csv junta o conteúdo de file_1.csv e file_2.csv em target_file.csv, adicionando file_2.csv ao final de file_1.csv.
O arquivo de cabeçalho não está no dataset original, então você precisa criá-lo. Para isso, use echo para gravar a lista de nomes de colunas separados por vírgula em um arquivo header.csv.
Neste exemplo, você usou o redirecionamento > do shell para despejar a saída do cat no arquivo adult.csv. O > cria um arquivo ou substitui todo o seu conteúdo se ele já existir. Ao dobrar o símbolo, >>, o novo conteúdo é acrescentado ao arquivo existente sem apagar o que já havia.
Agora vamos adicionar o header.csv no início de adult.data. Ao mesmo tempo, renomeie adult.data para adult.csv, já que, no fim das contas, é um arquivo CSV.
Outro cenário frequente em data mining é quando um arquivo está corrompido ou mal formatado, por exemplo com caracteres fora de UTF-8 ou uma vírgula fora do lugar. Você pode corrigir o arquivo sem abri-lo usando o comando sed.
O padrão genérico do sed é
$ sed"s/<string to replace>/<string to replace it with>/g"<source_file>><target_file>.Tecnologia
O dataset adult.csv usa o caractere ? para indicar valor ausente. Você pode substituir esse caractere por um valor padrão mais adequado usando sed. A string vazia é preferível como indicação de valor ausente, pois será interpretada como NaN ao carregar os dados em um DataFrame do Pandas.
Isso retorna a contagem de 2.399 linhas com pelo menos uma coluna com valor ausente indicado por ?. O comando a seguir vai substituir todas as colunas com ? por string vazia. Todas as células que contêm apenas ? seguido de um espaço agora ficarão realmente vazias.
Note que usamos o delimitador de coluna , nas strings de origem e destino para evitar substituir pontos de interrogação legítimos que possam existir em outras partes do dataset.
Crie um subconjunto de um arquivo grande
Imagine agora que você está lidando com um arquivo com mais de 30 milhões de linhas. Enquanto desenvolve seu script em Python ou R, você vai querer testar seu fluxo de trabalho apenas em uma amostra do arquivo original, sem carregar tudo na memória. Você pode usar uma combinação de head e tail para criar um subamostra do dataset original.
head mostra o início dos arquivos;
tail mostra o final dos arquivos
Como vimos, esses comandos aceitam a flag -n (de --lines) para limitar o número de linhas na saída. tail também aceita a flag -f (de --follow) para exibir dados à medida que são acrescentados ao fim do arquivo. Isso é especialmente útil para monitorar arquivos de log enquanto seus scripts estão rodando, com tail -f <logfile>.
Misturando o pipe | com head e tail, você pode extrair um certo número de linhas de dentro de um arquivo e exportar o conteúdo para um arquivo de subconjunto. Por exemplo, para extrair 20 linhas a partir da linha 100:
Repare que primeiro você pega primeira_linha + numero_de_linhas com head e depois usa tail para obter o numero_de_linhas. O comando genérico é:
$ head -n <total_lines><source_file>| tail -n <number_of_lines>><target_file>Tecnologia
onde total_lines = first_line + number_of_lines. Entretanto, seu novo arquivo amostrado não contém mais o cabeçalho. Já sabemos como recolocar o cabeçalho no arquivo de subconjunto usando cat para concatenar o arquivo e o header.csv criado antes:
Note que você não usou o nome de origem adult\_sample.csv como arquivo de destino; em vez disso, criou um novo arquivo chamado adult\_sample\_with\_header.csv. Usar o mesmo nome de um dos arquivos de origem como destino ao rodar cat pode gerar conteúdo inesperado. É melhor criar um novo arquivo como saída do cat.
Encontrando duplicatas com uniq
Com o comando uniq você encontra linhas repetidas adjacentes em um arquivo. O uniq tem várias flags; as mais úteis são:
uniq -c: adiciona a contagem de repetições a cada linha;
uniq -d: mostra apenas as linhas duplicadas; e
uniq -u: mostra apenas as linhas únicas.
Porém, uniq não é "inteligente": linhas repetidas não serão detectadas se não estiverem adjacentes. Ou seja, antes você precisa sortear o arquivo. Este comando conta o número de linhas duplicadas em adult.csv:
e mostra que há 23 duplicatas. O próximo comando pega todas as linhas com contagem de repetição, ordena em ordem reversa e exibe as 3 duplicatas mais frequentes:
Há muitas combinações poderosas ao juntar sort e uniq com diferentes flags. Use man sort e man uniq para explorar mais.
Selecionando colunas com cut
O bom de arquivos CSV e comandos de shell é que você também pode trabalhar no nível de colunas usando cut para selecionar uma coluna específica. cut recebe duas flags principais: -d para especificar o delimitador de coluna e -f para especificar as colunas desejadas. No exemplo a seguir, usamos cut para descobrir quantos valores únicos a variável categórica workclass (coluna 2) assume.
Primeiro selecione a coluna workclass e faça um pipe para head para verificar se é a coluna certa:
O que indica, por exemplo, que há 1.837 valores nulos e que a classe principal, de longe, é Private com 22.969 ocorrências.
A linha de comando acima é semelhante ao método value_counts() aplicado a uma Series do DataFrame com os dados do adult.csv.
Laços (looping)
Até aqui, trabalhamos principalmente com um arquivo. Para renomear, processar ou transferir grandes quantidades de arquivos, vale acrescentar laços ao seu kit de shell. O formato genérico de um loop no bash é:
Escrever loops e usar variáveis abre caminho para manipulações de arquivos mais complexas e é a porta de entrada para o shell scripting, que vai além deste artigo introdutório. Mas saiba que shell scripting é simples o suficiente se você começar pequeno e evoluir conforme ganha confiança.
Conclusão
Linhas de comando em shell são extremamente úteis no seu dia a dia como cientista de dados. Há muitos outros exemplos e casos de uso a explorar. E, como você vai perceber, quase sempre existem diferentes maneiras de chegar ao mesmo resultado usando a ampla variedade de comandos e flags disponíveis. Nesses casos, manter a solução simples costuma ser a melhor estratégia.
Tomara que os exemplos apresentados aqui ajudem você a incorporar comandos de shell ao seu kit de processamento de dados. Fale comigo e compartilhe seus truques de shell no Twitter: @alexip.
As ferramentas essenciais de ciência de dados para iniciantes e profissionais da área para coletar, processar, analisar, visualizar e modelar os dados de forma eficiente.
Todos os cientistas de dados precisam ter experiência em Python, mas quais habilidades são as mais importantes para eles dominarem? Descubra as dez habilidades mais importantes em Python no último resumo.
Aprenda sobre as ferramentas Python essenciais para o desenvolvimento de software, raspagem e desenvolvimento da Web, análise e visualização de dados e aprendizado de máquina.
Encontre o IDE Python perfeito para suas necessidades de ciência de dados em 2026. Compare recursos, benefícios e desempenho para fazer uma escolha informada e segura.
Existem muitos cenários em que você precisa analisar, modificar e processar rapidamente arquivos grandes, tanto em quantidade quanto em tamanho. Esses arquivos costumam ser CSV (Comma Separated Values) em texto puro. Abrir esse tipo de arquivo em planilhas como Excel, LibreOffice ou OpenOffice pode estourar a memória da sua máquina. Além disso, processar muitos arquivos em lote costuma falhar depois de algumas horas por conta de alguma anomalia inesperada.
Você inevitavelmente perde muito tempo com telas travadas, reinicializações e longas esperas.
Só que a maioria dessas tarefas poderia ser feita com poucas linhas de código. Mais ainda: estar familiarizado com alguns comandos simples de shell pode economizar muito tempo e reduzir a frustração.
Este post traz uma visão geral de alguns comandos de shell que eu uso praticamente todos os dias. Espero que sejam úteis para você.
Anotações rápidas
Atenção: existem diferentes tipos de shell (bash, zsh, ...). O bash é o mais comum, pois é o shell padrão no OS X e nas principais distribuições Linux. O Zsh (e o Oh My Zsh) é uma alternativa popular e poderosa. Os comandos de shell deste post foram testados no bash no OS X (macOS) e devem funcionar em outros shells e ambientes.
Todos os exemplos a seguir usam o conjunto de dados adult do repositório UCI Machine Learning, também conhecido como "Census Income", disponível aqui. Esse dataset é comumente usado para prever se a renda excede \$50K/ano com base em dados do censo. Com 48.842 linhas e 14 atributos, não é um dataset grande, mas é suficiente para ilustrar os exemplos. Embora o arquivo tenha a extensão
.data, ele é um CSV bem formatado. Fique à vontade para baixar e acompanhar!Conte com
wcDado um novo arquivo de texto, você quer saber quantas linhas ele tem. Isso pode ser feito com o comando de contagem de palavras
wc -l:O que indica que o arquivo
adult.datacontém 32.562 linhas. A flag-linstrui owca contar linhas. Você também pode usarwcpara contar palavras com a flag-w.O arquivo
adult.datacontém quase 500 mil palavras.O comando
wctambém pode contar quantos arquivos há em um diretório usando a saída de um simplesls -lcomo entrada para owc. Usar a saída de um comando como entrada para outro com o pipe|é um padrão útil chamado pipelining. Você vai vê-lo em vários exemplos neste post.Suponha agora que você tenha uma pasta com muitos arquivos. O comando abaixo informa exatamente quantos itens ela contém:
Há muitas outras aplicações para o
wcquando você começa a usar curingas e subpastas.Voltando ao arquivo
adult.data, vamos olhar as primeiras linhas com o comandohead. Por padrão,headexibe 10 linhas; você pode limitar a saída às 2 primeiras com a flag-n.Note que o arquivo não tem linha de cabeçalho. Os nomes das colunas não estão no arquivo. Você pode adicionar essa linha de cabeçalho concatenando dois arquivos com o comando
cat.Concatene arquivos com
catO comando
catimprime o conteúdo de um arquivo na saída padrão (ou seja, no terminal). Ele também pode concatenar uma série de arquivos. O comandocat file_1.csv file_2.csv > target_file.csvjunta o conteúdo defile_1.csvefile_2.csvemtarget_file.csv, adicionandofile_2.csvao final defile_1.csv.O arquivo de cabeçalho não está no dataset original, então você precisa criá-lo. Para isso, use
echopara gravar a lista de nomes de colunas separados por vírgula em um arquivoheader.csv.Neste exemplo, você usou o redirecionamento
>do shell para despejar a saída docatno arquivoadult.csv. O>cria um arquivo ou substitui todo o seu conteúdo se ele já existir. Ao dobrar o símbolo,>>, o novo conteúdo é acrescentado ao arquivo existente sem apagar o que já havia.Agora vamos adicionar o
header.csvno início deadult.data. Ao mesmo tempo, renomeieadult.dataparaadult.csv, já que, no fim das contas, é um arquivo CSV.Confira se a primeira linha de
adult.csvcontém os nomes das colunas com:Modifique um arquivo com
sedOutro cenário frequente em data mining é quando um arquivo está corrompido ou mal formatado, por exemplo com caracteres fora de UTF-8 ou uma vírgula fora do lugar. Você pode corrigir o arquivo sem abri-lo usando o comando
sed.O padrão genérico do
sedéO dataset
adult.csvusa o caractere?para indicar valor ausente. Você pode substituir esse caractere por um valor padrão mais adequado usandosed. A string vazia é preferível como indicação de valor ausente, pois será interpretada comoNaNao carregar os dados em um DataFrame do Pandas.Isso retorna a contagem de 2.399 linhas com pelo menos uma coluna com valor ausente indicado por
?. O comando a seguir vai substituir todas as colunas com?por string vazia. Todas as células que contêm apenas?seguido de um espaço agora ficarão realmente vazias.Note que usamos o delimitador de coluna
,nas strings de origem e destino para evitar substituir pontos de interrogação legítimos que possam existir em outras partes do dataset.Crie um subconjunto de um arquivo grande
Imagine agora que você está lidando com um arquivo com mais de 30 milhões de linhas. Enquanto desenvolve seu script em Python ou R, você vai querer testar seu fluxo de trabalho apenas em uma amostra do arquivo original, sem carregar tudo na memória. Você pode usar uma combinação de
headetailpara criar um subamostra do dataset original.headmostra o início dos arquivos;tailmostra o final dos arquivosComo vimos, esses comandos aceitam a flag
-n(de--lines) para limitar o número de linhas na saída.tailtambém aceita a flag-f(de--follow) para exibir dados à medida que são acrescentados ao fim do arquivo. Isso é especialmente útil para monitorar arquivos de log enquanto seus scripts estão rodando, comtail -f <logfile>.Misturando o pipe
|comheadetail, você pode extrair um certo número de linhas de dentro de um arquivo e exportar o conteúdo para um arquivo de subconjunto. Por exemplo, para extrair 20 linhas a partir da linha 100:Repare que primeiro você pega primeira_linha + numero_de_linhas com
heade depois usatailpara obter o numero_de_linhas. O comando genérico é:onde
total_lines = first_line + number_of_lines. Entretanto, seu novo arquivo amostrado não contém mais o cabeçalho. Já sabemos como recolocar o cabeçalho no arquivo de subconjunto usandocatpara concatenar o arquivo e oheader.csvcriado antes:Note que você não usou o nome de origem
adult\_sample.csvcomo arquivo de destino; em vez disso, criou um novo arquivo chamadoadult\_sample\_with\_header.csv. Usar o mesmo nome de um dos arquivos de origem como destino ao rodarcatpode gerar conteúdo inesperado. É melhor criar um novo arquivo como saída docat.Encontrando duplicatas com
uniqCom o comando
uniqvocê encontra linhas repetidas adjacentes em um arquivo. Ouniqtem várias flags; as mais úteis são:uniq -c: adiciona a contagem de repetições a cada linha;uniq -d: mostra apenas as linhas duplicadas; euniq -u: mostra apenas as linhas únicas.Porém,
uniqnão é "inteligente": linhas repetidas não serão detectadas se não estiverem adjacentes. Ou seja, antes você precisasortear o arquivo. Este comando conta o número de linhas duplicadas emadult.csv:e mostra que há 23 duplicatas. O próximo comando pega todas as linhas com contagem de repetição, ordena em ordem reversa e exibe as 3 duplicatas mais frequentes:
Há muitas combinações poderosas ao juntar
sorteuniqcom diferentes flags. Useman sorteman uniqpara explorar mais.Selecionando colunas com
cutO bom de arquivos CSV e comandos de shell é que você também pode trabalhar no nível de colunas usando
cutpara selecionar uma coluna específica.cutrecebe duas flags principais:-dpara especificar o delimitador de coluna e-fpara especificar as colunas desejadas. No exemplo a seguir, usamoscutpara descobrir quantos valores únicos a variável categóricaworkclass(coluna 2) assume.Primeiro selecione a coluna
workclasse faça um pipe paraheadpara verificar se é a coluna certa:Agora, para contar os valores únicos, ordene a saída do cut e envie para
uniq -c, assim:O que indica, por exemplo, que há 1.837 valores nulos e que a classe principal, de longe, é
Privatecom 22.969 ocorrências.A linha de comando acima é semelhante ao método
value_counts()aplicado a uma Series do DataFrame com os dados doadult.csv.Laços (looping)
Até aqui, trabalhamos principalmente com um arquivo. Para renomear, processar ou transferir grandes quantidades de arquivos, vale acrescentar laços ao seu kit de shell. O formato genérico de um loop no bash é:
Vamos colocar isso em prática. Imagine que você tem 1000 arquivos com espaços no nome e quer substituir cada espaço por um sublinhado "_".
Neste exemplo,
replace_sourceereplace_targetcomo placeholders para o espaço e o sublinhado*.csvna pasta atualfilename, criamos umnew_filenamesubstituindo cada espaço por um sublinhadomvOu seja, além de usar o shell para percorrer arquivos em um diretório, você também criou variáveis.
Variáveis
Vamos encerrar esta introdução a comandos de shell falando de variáveis. Criar variáveis no shell é simples:
Por exemplo:
Note que não há espaço ao redor do sinal de '='.
var = '<a string>'não funciona. Para retornar o valor da variável, basta usarecho:E para usá-la em um script, encapsule-a entre aspas, como vimos:
Escrever loops e usar variáveis abre caminho para manipulações de arquivos mais complexas e é a porta de entrada para o shell scripting, que vai além deste artigo introdutório. Mas saiba que shell scripting é simples o suficiente se você começar pequeno e evoluir conforme ganha confiança.
Conclusão
Linhas de comando em shell são extremamente úteis no seu dia a dia como cientista de dados. Há muitos outros exemplos e casos de uso a explorar. E, como você vai perceber, quase sempre existem diferentes maneiras de chegar ao mesmo resultado usando a ampla variedade de comandos e flags disponíveis. Nesses casos, manter a solução simples costuma ser a melhor estratégia.
Tomara que os exemplos apresentados aqui ajudem você a incorporar comandos de shell ao seu kit de processamento de dados. Fale comigo e compartilhe seus truques de shell no Twitter: @alexip.
Dê uma olhada no nosso tutorial Configure um ambiente de ciência de dados no seu computador.