Quais comandos alimentam um arquivo de texto delimitado por tabulação e cortam cada linha em 80 caracteres?


8

Tenho arquivos de texto com várias linhas de dados (às vezes) delimitados por tabulação. Gostaria de exibir o arquivo para que eu possa dar uma olhada nele - para ver apenas os primeiros 80 caracteres de cada linha (eu projetei o arquivo de texto para colocar os itens importantes em primeiro lugar em cada linha).

Eu pensei que poderia usar cat para ler cada linha do arquivo e enviar cada linha para o próximo comando em um pipe:

cat tabfile | cut -c -80

Mas isso parecia quebrado. Tentei pesquisar e o grep parecia funcionar - mas depois descobri que não, não (nem todas as linhas do arquivo tinham mais de 80 caracteres) - parece que as guias são contadas como caracteres únicos por corte.

Eu tentei:

cat tabfile | tr \t \040 | cut -c -80

Mesmo que isso alterasse um pouco meus dados, eliminando a legibilidade do espaço em branco. Mas isso não funcionou. Nem:

cat tabfile | tr \011 \040 | cut -c -80

Talvez eu esteja usando tr errado? Eu já tive problemas com tr antes, querendo remover vários espaços (a versão do tr à qual tenho acesso nesta máquina tem uma opção -s para espremer vários caracteres - talvez seja necessário brincar mais com ela)

Tenho certeza de que, se eu errei, poderia usar perl, awk ou sed, ou algo para fazer isso.

No entanto, eu gostaria de uma solução que use comandos regulares (POSIX?), Para que seja o mais portátil possível. Se eu acabar usando tr, provavelmente tentaria transformar tabulações em caracteres, talvez faça um cálculo, recorte o cálculo e depois transforme esses caracteres em tabulações para a saída.

Não precisa ser uma única linha / inserida diretamente na linha de comando - um script é adequado.


Mais informações sobre tab-files:

Uso tab para quebrar campos, porque um dia talvez eu queira importar dados para outro programa. Então, eu tendem a ter apenas uma guia entre partes do conteúdo. Mas também uso guias para alinhar as coisas com colunas verticais, para ajudar na legibilidade ao olhar para o arquivo de texto sem formatação. O que significa que, para alguns trechos de texto, preencho o final do conteúdo com espaços até chegar onde a guia funcionará, alinhando o próximo campo com os acima e abaixo dele.

DarkTurquoise # 00CED1 Mares, céus, barcos a remos Natureza
MediumSpringGreen # 00FA9A Útil para árvores Magia  
Cal # 00FF00 Apenas para uso em galinhas de primavera e US $

Então você quer 80 caracteres contando a largura da guia? Você pode substituir as guias por uma contagem apropriada de espaços e usar recortar.
muru

Annnnnd, como posso (facilmente) expandir um único caractere com vários caracteres? Ou, mais importante, com uma quantidade variável de caracteres (dependendo de quantos outros caracteres estão na linha), pois eu uso a guia para alinhar coisas verticalmente com diferentes quantidades de informações antes / depois de cada guia. Como eu disse, se eu quisesse aprender perl / awk / sed, tenho certeza que poderia, mas gostaria de algo simples
user3082

Você poderia tentar pra partir de coreutils: pr -1 -t -l200 -W80 file. Aumente / diminua o comprimento da página (número depois -l) conforme sua necessidade.
31514 Don_crissti

Don, sua sugestão (por que não é uma resposta?) Me dá uma boa mensagem de erro. Mas o homem diz "pré-imprima arquivos", então analisando isso.
user3082

Don, faça disso uma resposta e vamos discutir isso lá. Eu tenho algo parecido com o seu - principalmente o mesmo formato, principalmente os mesmos sinalizadores: -w em vez de -W, etc ...
user3082

Respostas:


9

Eu acho que você está procurando expande / ou unexpand. Parece que você está tentando garantir que uma \tlargura ab conte 8 caracteres em vez do único. foldfará isso também, mas envolverá sua entrada na próxima linha, em vez de truncá-la. Eu acho que você quer:

expand < input | cut -c -80

expande unexpandsão ambos POSIX especificados :

  • O expandutilitário deve gravar arquivos ou a entrada padrão na saída padrão com os \tcaracteres ab substituídos por um ou mais caracteres de espaço necessários para preencher a próxima tabulação. Quaisquer caracteres de backspace devem ser copiados para a saída e fazer com que a contagem da posição da coluna para os cálculos de tabulação seja diminuída; a contagem da posição da coluna não deve ser diminuída abaixo de zero.

Bem simples. Então, veja aqui o que isso faz:

unset c i; set --;                                                             
until [ "$((i+=1))" -gt 10 ]; do set -- "$@" "$i" "$i"; done                      
for c in 'tr \\t \ ' expand;  do eval '                                           
    { printf "%*s\t" "$@"; echo; } | 
      tee /dev/fd/2 |'"$c"'| { 
      tee /dev/fd/3 | wc -c >&2; } 3>&1 |
      tee /dev/fd/2 | cut -c -80'
done

O untilloop na parte superior obtém um conjunto de dados como ...

1 1 2 2 3 3 ...

É printfisso com o %*ssinalizador de preenchimento de arg, de modo que cada um dos membros do conjunto printfseja preenchido com tantos espaços quanto o número do argumento. Para cada um, acrescenta um \tcaractere ab.

Todos os tees são usados ​​para mostrar os efeitos de cada filtro quando aplicado.

E os efeitos são estes:

1        2        3        4        5        6        7        8                9               10
1  2   3    4     5      6       7        8         9         10 
1  2   3    4     5      6       7        8         9         10 
66
1        2        3        4        5        6        7        8                9               10
1        2        3        4        5        6        7        8                9               10 
1        2        3        4        5        6        7        8                
105

Essas linhas são alinhadas em dois conjuntos como ...

  1. saída de printf ...; echo
  2. saída tr ...ouexpand
  3. saída de cut
  4. saída de wc

As quatro principais linhas são os resultados do trfiltro - no qual cada \tab é convertido em um único espaço .

E no fundo quatro os resultados da expandcadeia.


1
Na verdade, não me importo (muito) se o \ t é contado como 8 (5?) Ou um, só que ele não é contado como um e exibido como 8.
user3082

+ @ anon3202 - faz todo o sentido. Entendo o que você quer dizer - (e tab stop length é a opção cli, por sinal) - eu simplesmente não disse isso da melhor maneira possível. Espero que você entenda a essência - como eu entendo, você pode ter.
mikeserv

Eu não segui bem a explicação, mas acompanhar os shows de expansão é definitivamente o que eu estava procurando.
user3082

3

Como as guias são mais para alinhamento do que para delimitação, uma maneira poderia ser usar columne depois cut:

column -s '\t' -t <some-file | cut -c -80

Parece que columnnão é POSIX. É parte dos utilitários BSD no Ubuntu, então suponho que seja bastante multiplataforma.


Usando columnesse modo, o OP nem precisaria adicionar espaços manualmente para alinhar.
Beni Cherniavsky-Paskin

1

A sugestão de Don nos comentários foi um bom começo.

Isto é o que eu precisava para fazê-lo (principalmente) funcionar:

pr +1 -1 -t -m -l1000 -w 80 tabfile

A -mera necessário para tornar o -wefeito bandeira tomada em uma única coluna. A página de manual pode usar alguma reescrita para indicar isso.

Ao tentar uma solução alternativa, descobri que prgera \tcaracteres, alimentando seus resultados para cutresultar no mesmo problema.

-1 (o sinalizador da coluna) diz especificamente na página de manual:

Esta opção não deve ser usada com -m.

No entanto, sem essa opção, as prlinhas são cortadas à vontade, muito mais curtas que o comprimento especificado.

prtambém insere um espaço antes (ou depois?) de cada palavra em um campo (ou seja, todo lugar que eu tenho um único espaço, tem dois após o processamento). Se houver muitas palavras, os espaços inseridos ignoram a -wrestrição (criando quebra automática). Mas, curiosamente, as 'colunas' delimitadas por tabulações não separadas por tabulações (alinhadas por espaços em branco) permanecem alinhadas.



0

Um utilitário que deve estar realmente ciente da largura da tela é fold: infelizmente, não parece ter uma opção para descartar em vez de quebrar. Embora seja provavelmente terrivelmente ineficiente, você pode, no entanto, fazer algo como

while read -r line; do fold -w80 <<< "$line" | head -n1; done < file
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.