Quelle (s) commande (s) alimentera un fichier texte délimité par des tabulations et coupera chaque ligne en 80 caractères?

8

J'ai des fichiers texte sur plusieurs lignes de données (parfois) délimitées par des tabulations. Je voudrais sortir le fichier afin que je puisse y jeter un coup d'œil - donc je voudrais seulement voir les 80 premiers caractères de chaque ligne (j'ai conçu le fichier texte pour mettre les choses importantes en premier sur chaque ligne).

J'avais pensé que je pouvais utiliser cat pour lire chaque ligne du fichier et envoyer chaque ligne à la commande suivante dans un pipe:

cat tabfile | cut -c -80

Mais cela semblait cassé. J'ai essayé de faire des singes, et grep semble fonctionner - mais j'ai découvert que non, ce n'était pas le cas (toutes les lignes du fichier ne comptaient pas plus de 80 caractères) - il semble que les onglets soient comptés comme des caractères uniques par coupe.

J'ai essayé:

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

Même si cela altérerait un peu mes données, en éliminant la lisibilité des espaces blancs. Mais cela n'a pas fonctionné. Pas plus:

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

Peut-être que j'utilise tr mal? J'ai eu des problèmes avec tr auparavant, je voulais supprimer plusieurs espaces (la version de tr à laquelle j'ai accès sur cette machine semble avoir une option -s pour presser plusieurs caractères - je devrais peut-être jouer avec)

Je suis sûr que si je déconnais, je pourrais utiliser perl, awk ou sed, ou quelque chose pour le faire.

Cependant, j'aimerais une solution qui utilise des commandes régulières (POSIX?), Afin qu'elle soit aussi portable que possible. Si je finis par utiliser tr, j'essaierais probablement de transformer les onglets en caractères, peut-être de faire un calcul, de couper le calcul, puis de reconvertir ces caractères en onglets pour la sortie.

Il n'a pas besoin d'être une seule ligne / entré directement sur la ligne de commande - un script est très bien.


Plus d'informations sur les fichiers à onglets:

J'utilise tab pour casser les champs, car un jour je souhaiterai peut-être importer des données dans un autre programme. J'ai donc tendance à n'avoir qu'un seul onglet entre les éléments de contenu. Mais j'utilise également des onglets pour aligner les choses avec les colonnes verticales, pour aider à la lisibilité lorsque vous regardez le fichier texte brut. Ce qui signifie que pour certains morceaux de texte, je garnis la fin du contenu avec des espaces jusqu'à ce que l'onglet fonctionne en alignant le champ suivant avec ceux au-dessus et en dessous.

DarkTurquoise # 00CED1 Mers, cieux, chaloupes Nature
MediumSpringGreen # 00FA9A Utile pour les arbres Magic  
Lime # 00FF00 Uniquement pour les poulets de printemps et fru $
user3082
la source
Vous voulez donc 80 caractères en comptant la largeur de tabulation? Vous pouvez remplacer les tabulations par un nombre approprié d'espaces, puis utiliser couper.
muru
Annnnnd, comment puis-je (facilement) développer un seul caractère avec plusieurs caractères? Ou, plus important encore, avec un nombre variable de caractères (en fonction du nombre d'autres caractères dans la ligne), car j'utilise l'onglet pour aligner verticalement des choses avec différentes quantités d'informations avant / après chaque onglet. Comme je l'ai dit, si je voulais apprendre perl / awk / sed, je suis sûr que je le pourrais, mais j'aimerais quelque chose de simple
user3082
Vous pouvez essayer prde coreutils: pr -1 -t -l200 -W80 file. Augmentez / diminuez la longueur de la page (nombre après -l) selon vos besoins.
don_crissti
Don, votre suggestion (pourquoi n'est-ce pas une réponse?) Me donne un joli message d'erreur. Mais l'homme dit "pré-imprimer les fichiers", alors regardez cela.
user3082
Don, fais-en une réponse et discutons-en là. J'ai quelque chose qui ressemble beaucoup au vôtre - principalement le même format, principalement les mêmes drapeaux: -w au lieu de -W, etc ...
user3082

Réponses:

9

Je pense que vous cherchez expandet / ou unexpand. Il semble que vous essayez de vous assurer qu'une \tlargeur ab compte pour 8 caractères plutôt que pour l'unique. foldle fera également, mais il encapsulera son entrée sur la ligne suivante plutôt que de la tronquer. Je pense que tu veux:

expand < input | cut -c -80

expandet unexpandsont tous deux spécifiés POSIX :

  • L' expandutilitaire doit écrire des fichiers ou l'entrée standard dans la sortie standard avec des \tcaractères ab remplacés par un ou plusieurs caractères d' espace nécessaires pour passer à la tabulation suivante. Tout caractère de retour arrière doit être copié dans la sortie et entraîner la décrémentation du décompte de position de colonne pour les calculs de tabulation; le décompte de position de colonne ne doit pas être décrémenté en dessous de zéro.

Assez simple. Alors, voici un aperçu de ce que cela fait:

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

La untilboucle en haut obtient un ensemble de données comme ...

1 1 2 2 3 3 ...

Il s'agit printfde l' %*sindicateur de remplissage d'argument, donc pour chacun de ceux de l'ensemble, il y printfaura autant d'espaces que le nombre d'arguments. À chacun, il ajoute un \tcaractère ab.

Tous les tees sont utilisés pour montrer les effets de chaque filtre lors de son application.

Et les effets sont les suivants:

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

Ces rangées sont alignées en deux ensembles comme ...

  1. sortie de printf ...; echo
  2. sortie de tr ...ouexpand
  3. sortie de cut
  4. sortie de wc

Les quatre premières rangées sont les résultats du trfiltre - dans lequel chaque \tab est converti en un seul espace .

Et les quatre derniers résultats de la expandchaîne.

mikeserv
la source
1
En fait, peu importe (trop) si le \ t est compté comme 8 (5?) Ou un, juste qu'il n'est pas compté comme un et affiché comme 8.
user3082
+ @ anon3202 - est parfaitement logique. Je comprends ce que vous voulez dire - (et la longueur de la tabulation est une option cli, en passant) - je ne l'ai pas dit aussi bien que je l'aurais pu. J'espère que vous obtenez l'essentiel - comme je le suppose, vous pourriez l'avoir.
mikeserv
Je n'ai pas tout à fait suivi l'explication, mais monkey avec expansion montre que l'expansion est certainement ce que je cherchais.
user3082
3

Étant donné que les onglets sont plus destinés à l'alignement qu'à la délimitation, une façon pourrait être d'utiliser columnpuis cut:

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

Il semble que ce columnne soit pas POSIX. Il fait partie des utilitaires BSD sur Ubuntu, donc je suppose que c'est assez multiplateforme.

muru
la source
De columncette façon, OP n'aurait même pas besoin d'ajouter manuellement des espaces pour s'aligner.
Beni Cherniavsky-Paskin
1

La suggestion de Don dans les commentaires était un bon début.

Voici ce dont j'avais besoin pour que cela fonctionne (principalement):

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

Le -métait nécessaire pour que le -wdrapeau prenne effet sur une seule colonne. La page de manuel pourrait utiliser une réécriture pour indiquer cela.

En essayant une solution de contournement, j'ai trouvé que les caractères prsortaient \t, donc nourrir ses résultats cutentraînait le même problème.

-1 (l'indicateur de colonne) dit spécifiquement dans la page de manuel:

Cette option ne doit pas être utilisée avec -m.

Cependant, sans cette option, les prlignes sont tronquées à volonté, à une longueur beaucoup plus courte que la longueur spécifiée.

prinsère également un espace avant (ou après?) chaque mot dans un champ (c'est-à-dire que chaque endroit où j'ai un seul espace, en a deux après le traitement). S'il y a trop de mots, les espaces insérés ignorent la -wrestriction (création d'un bouclage). Mais, curieusement, les «colonnes» autrement non délimitées par des tabulations (c'est-à-dire disposées en espaces blancs) restent alignées.

user3082
la source
0

En utilisant awk:

awk '{ $0 = substr($0, 1, 80) }1' file

Basé sur la réponse de Chris Down ici .

jasonwryan
la source
Le mord sur les \ t - Mais ce lien semble prometteur
user3082
0

Un utilitaire qui devrait être vraiment conscient de la largeur d'affichage est fold: malheureusement, il ne semble pas avoir une option à ignorer au lieu d'envelopper. Bien qu'il soit probablement horriblement inefficace, vous pouvez cependant faire quelque chose comme

while read -r line; do fold -w80 <<< "$line" | head -n1; done < file
tournevis
la source