GNU/Linux >> Tutoriels Linux >  >> Linux

7 Utilisation essentielle et pratique de la commande Coller sous Linux

Dans un article précédent, nous avons parlé de la commande de coupe qui peut être utilisée pour extraire des colonnes d'un fichier de données texte CSV ou tabulaire.

Le paste La commande fait exactement le contraire :elle fusionne plusieurs fichiers d'entrée pour produire un nouveau fichier texte délimité à partir d'eux. Nous allons voir comment utiliser efficacement la commande Coller sous Linux et Unix.

7 exemples pratiques de la commande Coller sous Linux

Si vous préférez les vidéos, vous pouvez regarder cette vidéo expliquant les mêmes exemples de commandes Coller abordés dans cet article.

1. Coller des colonnes

Dans son cas d'utilisation le plus basique, le paste la commande prend N fichiers d'entrée et joignez-les ligne par ligne sur la sortie :

sh$ printf "%s\n" {a..e} | tee letters
a
b
c
d
e

sh$ printf "%s\n" {1..5} | tee digits
1
2
3
4
5

sh$ paste letters digits
a    1
b    2
c    3
d    4
e    5

Mais laissons maintenant les explications théoriques pour travailler sur un exemple pratique. Si vous avez téléchargé les exemples de fichiers utilisés dans la vidéo ci-dessus, vous pouvez voir que j'ai plusieurs fichiers de données correspondant aux différentes colonnes d'un tableau :

sh$ head -3 *.csv
==> ACCOUNTLIB.csv <==
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC

==> ACCOUNTNUM.csv <==
ACCOUNTNUM
623477
445452

==> CREDIT.csv <==
CREDIT
<--- empty line
<--- empty line

==> DEBIT.csv <==
DEBIT
00000001615,00
00000000323,00

Il est assez facile de produire un fichier texte délimité par des tabulations à partir de ces données :

sh$ paste *.csv | head -3
ACCOUNTLIB    ACCOUNTNUM    CREDIT    DEBIT
TIDE SCHEDULE    623477        00000001615,00
VAT BS/ENC    445452        00000000323,00

Comme vous pouvez le voir, lorsqu'il est affiché sur la console, le contenu de ce fichier de valeurs séparées par des tabulations ne produit pas un tableau parfaitement formaté. Mais c'est par conception :le paste La commande n'est pas utilisée pour créer des fichiers texte à largeur fixe, mais uniquement des fichiers texte délimités où un caractère donné se voit attribuer le rôle de séparateur de champs.

Donc, même si ce n'est pas évident dans la sortie ci-dessus, il y a en fait un et un seul caractère de tabulation entre chaque champ. Rendons cela évident en utilisant la commande sed :

sh$ paste *.csv | head -3 | sed -n l
ACCOUNTLIB\tACCOUNTNUM\tCREDIT\tDEBIT$
TIDE SCHEDULE\t623477\t\t00000001615,00$
VAT BS/ENC\t445452\t\t00000000323,00$

Désormais, les caractères invisibles sont affichés sans ambiguïté dans la sortie. Et vous pouvez voir les caractères de tabulation affichés sous la forme \t . Vous pouvez les compter :il y a toujours trois onglets sur chaque ligne de sortie — un entre chaque champ. Et quand vous en voyez deux d'affilée, cela signifie seulement qu'il y avait un champ vide là-bas. C'est souvent le cas dans mes fichiers d'exemple particuliers puisque sur chaque ligne, le champ CREDIT ou DEBIT est défini, mais jamais les deux en même temps.

2. Modification du délimiteur de champ

Comme nous l'avons vu, le paste La commande utilise le caractère de tabulation comme séparateur de champ par défaut ("délimiteur"). Quelque chose que nous pouvons changer en utilisant le -d option. Supposons que je souhaite utiliser un point-virgule à la place :

# The quotes around the ';' are used to prevent the
# shell to consider that semi-colon as being a command separator
sh$ paste -d ';' *.csv | head -3
ACCOUNTLIB;ACCOUNTNUM;CREDIT;DEBIT
TIDE SCHEDULE;623477;;00000001615,00
VAT BS/ENC;445452;;00000000323,00

Pas besoin d'ajouter le sed commande à la fin du pipeline ici puisque le séparateur que nous avons utilisé est un caractère imprimable. Quoi qu'il en soit, le résultat est le même :sur une ligne donnée, chaque champ est séparé de son voisin par un délimiteur à un caractère.

3. Transposer des données en utilisant le mode série

Les exemples ci-dessus ont une chose en commun :le paste La commande lit tous ses fichiers d'entrée en parallèle, ce qui est nécessaire pour pouvoir les fusionner ligne par ligne dans la sortie.

Mais le paste la commande peut également fonctionner en mode dit série , activé en utilisant le -s drapeau. Comme son nom l'indique, en mode série, le paste commande lira les fichiers d'entrée l'un après l'autre. Le contenu du premier fichier d'entrée sera utilisé pour produire la première ligne de sortie. Ensuite, le contenu du deuxième fichier d'entrée sera utilisé pour produire la deuxième ligne de sortie, et ainsi de suite. Cela signifie également que la sortie aura autant de lignes qu'il y avait de fichiers dans l'entrée.

Plus formellement, les données extraites du fichier N apparaîtra comme le N ème ligne dans la sortie en mode série, alors qu'elle apparaîtrait comme le N ème colonne en mode "parallèle" par défaut. Mathématiquement, la table obtenue en mode série est la transposée de la table produite en mode par défaut (et inversement ).

Pour illustrer cela, considérons un petit sous-échantillon de nos données :

sh$ head -5 ACCOUNTLIB.csv | tee ACCOUNTLIB.sample
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC
PAYABLES
ACCOMMODATION GUIDE
sh$ head -5 ACCOUNTNUM.csv | tee ACCOUNTNUM.sample
ACCOUNTNUM
623477
445452
4356
623372

En mode par défaut ("parallèle"), les données du fichier d'entrée serviront de colonnes dans la sortie, produisant un tableau de deux colonnes sur cinq lignes :

sh$ paste *.sample
ACCOUNTLIB    ACCOUNTNUM
TIDE SCHEDULE    623477
VAT BS/ENC    445452
PAYABLES    4356
ACCOMMODATION GUIDE    623372

Mais en mode série, les données du fichier d'entrée apparaîtront sous forme de lignes, produisant maintenant un tableau de cinq colonnes sur deux lignes :

sh$ paste -s *.sample
ACCOUNTLIB    TIDE SCHEDULE    VAT BS/ENC    PAYABLES    ACCOMMODATION GUIDE
ACCOUNTNUM    623477    445452    4356    623372

4. Travailler avec l'entrée standard

Comme beaucoup d'utilitaires standards, le paste La commande peut utiliser l'entrée standard pour lire les données. Soit implicitement lorsqu'il n'y a pas de nom de fichier donné en argument, soit explicitement en utilisant le spécial - nom de fichier. Apparemment, ce n'est pas très utile :

# Here, the paste command is useless
head -5 ACCOUNTLIB.csv | paste
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC
PAYABLES
ACCOMMODATION GUIDE

Je vous encourage à le tester par vous-même, mais la syntaxe suivante devrait produire le même résultat, rendant à nouveau la commande coller inutile dans ce cas :

head -5 ACCOUNTLIB.csv | paste -

Alors, quel pourrait être l'intérêt de lire des données à partir de l'entrée standard ? Eh bien, avec le -s drapeau, les choses deviennent beaucoup plus intéressantes comme nous allons le voir maintenant.

4.1. Joindre les lignes d'un fichier

Comme nous l'avons vu quelques paragraphes plus tôt, en mode série, la commande coller écrira toutes les lignes d'un fichier d'entrée sur la même ligne de sortie. Cela nous donne un moyen simple de joindre toutes les lignes lues à partir de l'entrée standard en une seule ligne de sortie (potentiellement très longue) :

sh$ head -5 ACCOUNTLIB.csv | paste -s -d':'
ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE

C'est essentiellement la même chose que vous pourriez faire en utilisant le tr commande, mais avec une différence cependant. Utilisons le diff utilitaire pour repérer cela :

sh$ diff <(head -5 ACCOUNTLIB.csv | paste -s -d':') \
         <(head -5 ACCOUNTLIB.csv | tr '\n' ':')
1c1
< ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE
---
> ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE:
\ No newline at end of file

Tel que rapporté par le diff utilitaire, nous pouvons voir le tr La commande a remplacé chaque instance du caractère de saut de ligne par le délimiteur donné, y compris le tout dernier. Par contre, le paste La commande gardait le dernier caractère de saut de ligne intact. Donc, selon que vous avez besoin ou non du délimiteur après le tout dernier champ, vous utiliserez une commande ou l'autre.

4.2. Formatage multi-colonnes d'un fichier d'entrée

Selon les spécifications de l'Open Group, "l'entrée standard doit être lue une ligne à la fois" par le paste commande. Ainsi, en passant plusieurs occurrences du - nom de fichier spécial comme arguments du paste la commande entraînera l'écriture d'autant de lignes consécutives de l'entrée dans la même ligne de sortie :

sh$ seq 9 | paste - - -
1    2    3
4    5    6
7    8    9

Pour rendre les choses plus claires, je vous encourage à étudier la différence entre les deux commandes ci-dessous. Dans le premier cas, la commande coller ouvre trois fois le même fichier, ce qui entraîne une duplication des données dans la sortie. Par contre, dans le second cas le fichier ACCOUNTLIB n'est ouvert qu'une seule fois (par le shell), mais lu trois fois pour chaque ligne (par le paste commande), ce qui entraîne l'affichage du contenu du fichier sur trois colonnes :

sh$ paste ACCOUNTLIB.csv ACCOUNTLIB.csv ACCOUNTLIB.csv | head -2
ACCOUNTLIB    ACCOUNTLIB    ACCOUNTLIB
TIDE SCHEDULE    TIDE SCHEDULE    TIDE SCHEDULE

sh$ paste - - - < ACCOUNTLIB.csv | head -2
ACCOUNTLIB    TIDE SCHEDULE    VAT BS/ENC
PAYABLES    ACCOMMODATION GUIDE    VAT BS/ENC

Étant donné le comportement du paste commande lors de la lecture à partir de l'entrée standard, ce n'est généralement pas conseillé d'utiliser plusieurs - noms de fichiers spéciaux en mode série. Dans ce cas, la première occurrence lira l'entrée standard jusqu'à sa fin, et les occurrences suivantes de - lirait à partir d'un flux d'entrée déjà épuisé, ce qui entraînerait l'absence de données supplémentaires :

# The following command will produce 3 lines of output.
# But the first one exhausted the standard input,
# so the remaining two lines are empty
sh$ seq 9 | paste -s - - -
1    2    3    4    5    6    7    8    9

5. Travailler avec des fichiers de longueur différente

Les spécifications Open Group pour le paste utilitaire sont assez clairs :

Si une condition de fin de fichier est détectée sur un ou plusieurs fichiers d'entrée, mais pas sur tous les fichiers d'entrée, coller se comportera comme si des lignes vides étaient lues à partir des fichiers sur lesquels la fin de fichier a été détectée, à moins que la -s l'option est spécifiée.

Ainsi, le comportement est celui auquel vous pouvez vous attendre :les données manquantes sont remplacées par du contenu « vide ». Pour illustrer ce comportement, enregistrons quelques transactions supplémentaires dans notre "base de données". Afin de conserver intacts les fichiers d'origine, nous travaillerons cependant sur une copie de nos données :

# Copy files
sh$ for f in ACCOUNTNUM ACCOUNTLIB CREDIT DEBIT; do
  cp ${f}.csv NEW${f}.csv
done

# Update the copy
sh$ cat - << EOF >> NEWACCOUNTNUM.csv
1080
4356
EOF

sh$ cat - << EOF >> NEWDEBIT.csv
00000001207,35

EOF

sh$ cat - << EOF >> NEWCREDIT.csv

00000001207,35
EOF

Avec ces mises à jour, nous avons maintenant enregistré un nouveau mouvement de capital du compte #1080 au compte #4356. Cependant, comme vous l'avez peut-être remarqué, je n'ai pas pris la peine de mettre à jour le fichier ACCOUNTLIB. Cela ne semble pas un si gros problème car le paste remplacera les lignes manquantes par des données vides :

sh$ paste -d';' NEWACCOUNTNUM.csv \
                NEWACCOUNTLIB.csv \
                NEWDEBIT.csv \
                NEWCREDIT.csv | tail
4356;PAYABLES;;00000000402,03
613866;RENTAL COSTS;00000000018,00;
4356;PAYABLES;;00000000018,00
657991;MISCELLANEOUS CHARGES;00000000015,00;
445333;VAT BS/DEBIT;00000000003,00;
4356;PAYABLES;;00000000018,00
626510;LANDLINE TELEPHONE;00000000069,14;
445452;VAT BS/ENC;00000000013,83;
1080;;00000001207,35; # <-- the account label is missing here
4356;;;00000001207,35 # <-- the account label is missing here

Mais attention, le paste la commande ne peut faire correspondre les lignes que par leur physique position :tout ce qu'il peut dire, c'est qu'un fichier est "plus court" qu'un autre. Pas les données manquent. Ainsi, il ajoute toujours les champs vides à la fin de la sortie, ce qui peut provoquer des décalages inattendus dans vos données. Rendons cela évident en ajoutant encore une autre transaction :

sh$ cat << EOF >> NEWACCOUNTNUM.csv
4356
3465
EOF

sh$ cat << EOF >> NEWACCOUNTLIB.csv
PAYABLES
WEB HOSTING
EOF

sh$ cat << EOF >> NEWDEBIT.csv

00000000706,48
EOF

sh$ cat << EOF >> NEWCREDIT.csv
00000000706,48

EOF

Cette fois, j'ai été plus rigoureux puisque j'ai correctement mis à jour à la fois le numéro de compte (ACCOUNTNUM), et son libellé correspondant (ACCOUNTLIB) ainsi que les fichiers de données CREDIT et DEBIT. Mais comme il manquait des données dans l'enregistrement précédent, le paste la commande n'est plus capable de garder les champs liés sur la même ligne :

sh$ paste -d';' NEWACCOUNTNUM.csv \
                NEWACCOUNTLIB.csv \
                NEWDEBIT.csv \
                NEWCREDIT.csv | tail
4356;PAYABLES;;00000000018,00
657991;MISCELLANEOUS CHARGES;00000000015,00;
445333;VAT BS/DEBIT;00000000003,00;
4356;PAYABLES;;00000000018,00
626510;LANDLINE TELEPHONE;00000000069,14;
445452;VAT BS/ENC;00000000013,83;
1080;PAYABLES;00000001207,35;
4356;WEB HOSTING;;00000001207,35
4356;;;00000000706,48
3465;;00000000706,48;

Comme vous pouvez le voir, le compte #4356 est signalé avec le libellé "HÉBERGEMENT WEB" alors qu'en réalité, ce dernier devrait apparaître sur la ligne correspondant au compte #3465.

En conclusion, si vous devez traiter des données manquantes, au lieu du paste commande, vous devriez envisager d'utiliser le join utilitaire car ce dernier correspondra aux lignes en fonction de leur contenu, et non en fonction de leur position dans le fichier d'entrée. Cela le rend beaucoup plus adapté aux applications de style "base de données". J'ai déjà publié une vidéo sur le join commande, mais cela devrait probablement mériter un article à part entière, alors faites-nous savoir si ce sujet vous intéresse !

6. Cycle sur les délimiteurs

Dans la très grande majorité des cas d'utilisation, vous ne fournirez qu'un seul caractère comme délimiteur. C'est ce que nous avons fait jusqu'à présent. Cependant, si vous donnez plusieurs caractères après le -d option, la commande coller les parcourra :le premier caractère sera utilisé comme premier délimiteur de champ sur la ligne, le deuxième caractère comme deuxième délimiteur de champ, et ainsi de suite.

sh$ paste -d':+-' ACCOUNT*.csv CREDIT.csv DEBIT.csv | head -5
ACCOUNTLIB:ACCOUNT NUM+CREDIT-DEBIT
TIDE SCHEDULE:623477+-00000001615,00
VAT BS/ENC:445452+-00000000323,00
PAYABLES:4356+00000001938,00-
ACCOMODATION GUIDE:623372+-00000001333,00

Les délimiteurs de champs ne peuvent apparaître qu'entre des champs. Pas au bout d'une ligne. Et vous ne pouvez pas insérer plus d'un délimiteur entre deux champs donnés. Comme astuce pour surmonter ces limitations, vous pouvez utiliser le /dev/null fichier spécial comme entrée supplémentaire où vous avez besoin d'un séparateur supplémentaire :

# Display the opening bracket between the
# ACCOUNTLIB field and the ACCOUNTNUM field, and
# the closing bracket between the ACCOUNTNUM field
# and the empty `/dev/null` field:
sh$ paste  -d'()' \
           ACCOUNT*.csv /dev/null | head -5
ACCOUNTLIB(ACCOUNTNUM)
TIDE SCHEDULE(623477)
VAT BS/ENC(445452)
PAYABLES(4356)
ACCOMODATION GUIDE(623372)

Quelque chose dont vous pourriez même abuser :

sh$ paste -d'# is ' \
          - ACCOUNTNUM.csv - - - ACCOUNTLIB.csv < /dev/null | tail -5
#657991 is MISCELLANEOUS CHARGES
#445333 is VAT BS/DEBIT
#4356 is PAYABLES
#626510 is LANDLINE TELEPHONE
#445452 is VAT BS/ENC

Cependant, inutile de dire que si vous atteignez ce niveau de complexité, cela pourrait être un indice du paste l'utilitaire n'était pas nécessairement le meilleur outil pour le travail. Peut-être vaut-il la peine d'envisager, dans ce cas, quelque chose d'autre comme sed ou la commande awk.

Mais que se passe-t-il si la liste contient moins de délimiteurs que nécessaire pour afficher une ligne dans la sortie ? Fait intéressant, le paste commande les "cyclera" dessus. Ainsi, une fois la liste épuisée, le paste La commande reviendra au premier délimiteur, ce qui ouvre probablement la porte à une utilisation créative. En ce qui me concerne, je n'ai rien pu faire de vraiment utile avec cette fonctionnalité compte tenu de mes données. Il faudra donc vous contenter de l'exemple un peu tiré par les cheveux suivant. Mais ce ne sera pas une perte de temps totale car c'était une bonne occasion de mentionner que vous devez doubler la barre oblique inverse (\\ ) lorsque vous souhaitez l'utiliser comme délimiteur :

sh$ paste -d'/\\' \
          - ACCOUNT*.csv CREDIT.csv DEBIT.csv - < /dev/null | tail -5
/MISCELLANEOUS CHARGES\657991/\00000000015,00/
/VAT BS/DEBIT\445333/\00000000003,00/
/PAYABLES\4356/00000000018,00\/
/LANDLINE TELEPHONE\626510/\00000000069,14/
/VAT BS/ENC\445452/\00000000013,83/

7. Délimiteurs de caractères multioctets

Comme la plupart des utilitaires Unix standard, la commande paste est née à un moment où un caractère équivalait à un octet. Mais ce n'est plus le cas :aujourd'hui, de nombreux systèmes utilisent par défaut l'encodage à longueur variable UTF-8. En UTF-8, un caractère peut être représenté par 1, 2, 3 ou 4 octets. Cela nous permet de mélanger dans le même fichier texte toute la variété de l'écriture humaine, ainsi que des tonnes de symboles et d'emojis, tout en maintenant une compatibilité ascendante avec l'ancien codage de caractères US-ASCII à un octet.

Disons par exemple que je voudrais utiliser le DIAMANT BLANC (◇ U+25C7) comme séparateur de champ. En UTF-8, ce caractère est codé à l'aide des trois octets e2 97 87 . Ce caractère peut être difficile à obtenir à partir du clavier, donc si vous voulez essayer par vous-même, je vous suggère de le copier-coller à partir du bloc de code ci-dessous :

# The sed part is only used as a little trick to add the
# row number as the first field in the output
sh$ sed -n = ACCOUNTNUM.csv |
       paste -d'◇' - ACCOUNT*.csv | tail -5
26�MISCELLANEOUS CHARGES�657991
27�VAT BS/DEBIT�445333
28�PAYABLES�4356
29�LANDLINE TELEPHONE�626510
30�VAT BS/ENC�445452

Assez trompeur, n'est-ce pas? Au lieu du diamant blanc attendu, j'ai ce symbole "point d'interrogation" (du moins, c'est ainsi qu'il est affiché sur mon système). Ce n'est cependant pas un personnage "aléatoire". C'est le caractère de remplacement Unicode utilisé "pour indiquer des problèmes lorsqu'un système est incapable de restituer un flux de données à un symbole correct" . Alors, qu'est-ce qui ne va pas ?

Encore une fois, l'examen du contenu binaire brut de la sortie nous donnera quelques indices :

sh$ sed -n = ACCOUNTNUM.csv | paste -d'◇' - ACCOUNT*.csv | tail -5 | hexdump -C
00000000  32 36 e2 4d 49 53 43 45  4c 4c 41 4e 45 4f 55 53  |26.MISCELLANEOUS|
00000010  20 43 48 41 52 47 45 53  97 36 35 37 39 39 31 0a  | CHARGES.657991.|
00000020  32 37 e2 56 41 54 20 42  53 2f 44 45 42 49 54 97  |27.VAT BS/DEBIT.|
00000030  34 34 35 33 33 33 0a 32  38 e2 50 41 59 41 42 4c  |445333.28.PAYABL|
00000040  45 53 97 34 33 35 36 0a  32 39 e2 4c 41 4e 44 4c  |ES.4356.29.LANDL|
00000050  49 4e 45 20 54 45 4c 45  50 48 4f 4e 45 97 36 32  |INE TELEPHONE.62|
00000060  36 35 31 30 0a 33 30 e2  56 41 54 20 42 53 2f 45  |6510.30.VAT BS/E|
00000070  4e 43 97 34 34 35 34 35  32 0a                    |NC.445452.|
0000007a

Nous avons déjà eu l'occasion de pratiquer avec les vidages hexadécimaux ci-dessus, donc vos yeux devraient maintenant être suffisamment aiguisés pour repérer les délimiteurs de champ dans le flux d'octets. En regardant bien, vous verrez que le séparateur de champs après le numéro de ligne est l'octet e2 . Mais si vous poursuivez vos recherches, vous remarquerez que le deuxième séparateur de champs est 97 . Non seulement le paste La commande n'a pas sorti le caractère que je voulais, mais elle n'a pas non plus utilisé partout le même octet que le séparateur ?!?

Attendez une minute :cela ne vous rappelle-t-il pas quelque chose dont nous avons déjà parlé ? Et ces deux octets e2 97 , ne vous sont-ils pas familiers ? Eh bien, familier est probablement un peu trop, mais si vous sautez quelques paragraphes en arrière, vous pourriez les trouver mentionnés quelque part…

Alors tu as trouvé où c'était ? Auparavant, je l'ai dit en UTF-8, le losange blanc est codé comme les trois octets e2 97 87 . Et en effet, le paste la commande a considéré cette séquence non pas comme un caractère entier de trois octets, mais comme trois caractères indépendants octets et donc, il a utilisé le premier octet comme premier séparateur de champ, puis le deuxième octet comme deuxième séparateur de champ.

Je vous laisse relancer cette expérience en ajoutant une colonne supplémentaire dans les données d'entrée ; vous devriez voir le troisième séparateur de champ être 87 — le troisième octet de la représentation UTF-8 pour le losange blanc.

Ok, c'est l'explication :le paste La commande n'accepte que des "caractères" d'un octet comme séparateur. Et c'est particulièrement ennuyeux, car, encore une fois, je ne connais aucun moyen de surmonter cette limitation, sauf en utilisant le /dev/null astuce que je t'ai déjà donnée :

sh$ sed -n = ACCOUNTNUM.csv |
    paste  -d'◇' \
           - /dev/null /dev/null \
           ACCOUNTLIB.csv /dev/null /dev/null \
           ACCOUNTNUM.csv | tail -5
26◇MISCELLANEOUS CHARGES◇657991
27◇VAT BS/DEBIT◇445333
28◇PAYABLES◇4356
29◇LANDLINE TELEPHONE◇626510
30◇VAT BS/ENC◇445452

Si vous avez lu mon article précédent sur la cut commande, vous vous souviendrez peut-être que j'ai eu des problèmes similaires avec l'implémentation GNU de cet outil. Mais j'ai remarqué à ce moment-là que l'implémentation d'OpenBSD prenait correctement en compte le LC_CTYPE paramètres régionaux pour identifier les caractères multi-octets. Par curiosité, j'ai testé le paste commande sur OpenBSD aussi. Hélas, avec le même résultat que sur ma box Debian cette fois, malgré les spécifications pour le paste utilitaire mentionnant la variable d'environnement LC_CTYPE comme déterminant " les paramètres régionaux pour l'interprétation des séquences d'octets de données textuelles en tant que caractères (par exemple, caractères à un octet par opposition aux caractères à plusieurs octets dans les arguments et les fichiers d'entrée)" . D'après mon expérience, toutes les implémentations majeures du paste l'utilitaire ignore actuellement les caractères multi-octets dans la liste des délimiteurs et suppose des séparateurs d'un octet. Mais je ne prétendrai pas avoir testé cela pour toute la variété des plateformes *nix. Donc si j'ai raté quelque chose ici, n'hésitez pas à utiliser la section des commentaires pour me corriger !

Astuce bonus :Éviter le piège \0

Pour des raisons historiques :

Les commandes :
coller -d "\0" …​ coller -d "" …​
ne sont pas nécessairement équivalents ; ce dernier n'est pas spécifié par ce volume de IEEE Std 1003.1-2001 et peut entraîner une erreur. La construction '\0' est utilisée pour signifier "pas de séparateur" car les versions historiques de paste ne suivaient pas les directives de syntaxe, et la commande :
coller -d”” …​
n'a pas pu être géré correctement par getopt().

Ainsi, le moyen portable de coller des fichiers sans utiliser de délimiteur consiste à spécifier le \0 délimiteur. Ceci est quelque peu contre-intuitif car, pour de nombreuses commandes, \0 signifie le caractère NUL - un caractère codé comme un octet composé uniquement de zéros qui ne doit entrer en conflit avec aucun contenu textuel.

Vous pouvez trouver le caractère NUL comme séparateur utile, en particulier lorsque vos données peuvent contenir des caractères arbitraires (comme lorsque vous travaillez avec des noms de fichiers ou des données fournies par l'utilisateur). Malheureusement, je ne connais aucun moyen d'utiliser le caractère NUL comme délimiteur de champ avec le paste commande. Mais peut-être savez-vous comment faire ? Si tel est le cas, je serais plus qu'heureux de lire votre solution dans la section de commande.

Par contre, le paste la partie implémentation de GNU Coreutils a le non-standard -z option pour passer de la nouvelle ligne au caractère NUL pour le séparateur de ligne. Mais dans ce cas, le caractère NUL sera utilisé comme séparateur de ligne les deux pour l'entrée et la sortie. Donc, pour tester cette fonctionnalité, nous avons d'abord besoin d'une version terminée par zéro de nos fichiers d'entrée :

sh$ tr '\n' '\0' < ACCOUNTLIB.csv > ACCOUNTLIB.zero
sh$ tr '\n' '\0' < ACCOUNTNUM.csv > ACCOUNTNUM.zero

Pour voir ce qui a changé dans le processus, nous pouvons utiliser le hexdump utilitaire pour examiner le contenu binaire brut des fichiers :

sh$ hexdump -C ACCOUNTLIB.csv | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 0a 54 49 44 45 20  |ACCOUNTLIB.TIDE |
00000010  53 43 48 45 44 55 4c 45  0a 56 41 54 20 42 53 2f  |SCHEDULE.VAT BS/|
00000020  45 4e 43 0a 50 41 59 41  42 4c 45 53 0a 41 43 43  |ENC.PAYABLES.ACC|
00000030  4f 4d 4f 44 41 54 49 4f  4e 20 47 55 49 44 45 0a  |OMODATION GUIDE.|
00000040  56 41 54 20 42 53 2f 45  4e 43 0a 50 41 59 41 42  |VAT BS/ENC.PAYAB|
sh$ hexdump -C ACCOUNTLIB.zero | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 00 54 49 44 45 20  |ACCOUNTLIB.TIDE |
00000010  53 43 48 45 44 55 4c 45  00 56 41 54 20 42 53 2f  |SCHEDULE.VAT BS/|
00000020  45 4e 43 00 50 41 59 41  42 4c 45 53 00 41 43 43  |ENC.PAYABLES.ACC|
00000030  4f 4d 4f 44 41 54 49 4f  4e 20 47 55 49 44 45 00  |OMODATION GUIDE.|
00000040  56 41 54 20 42 53 2f 45  4e 43 00 50 41 59 41 42  |VAT BS/ENC.PAYAB|

Je vous laisse comparer par vous-même les deux dumps hexadécimaux ci-dessus pour identifier la différence entre les fichiers « .zero » et les fichiers texte originaux. Comme indice, je peux vous dire qu'une nouvelle ligne est encodée sous la forme 0a octet.

J'espère que vous avez pris le temps nécessaire pour localiser le caractère NUL dans les fichiers d'entrée ".zero". Quoi qu'il en soit, nous avons maintenant une version terminée par zéro des fichiers d'entrée, nous pouvons donc utiliser le -z option du paste commande pour gérer ces données, produisant également dans la sortie un résultat terminé par zéro :

# Hint: in the hexadecimal dump:
#  the byte 00 is the NUL character
#  the byte 09 is the TAB character
# Look at any ASCII table to find the mapping
# for the letters or other symbols
# (https://en.wikipedia.org/wiki/ASCII#Character_set)
sh$ paste -z *.zero | hexdump -C | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 09 41 43 43 4f 55  |ACCOUNTLIB.ACCOU|
00000010  4e 54 4e 55 4d 00 54 49  44 45 20 53 43 48 45 44  |NTNUM.TIDE SCHED|
00000020  55 4c 45 09 36 32 33 34  37 37 00 56 41 54 20 42  |ULE.623477.VAT B|
00000030  53 2f 45 4e 43 09 34 34  35 34 35 32 00 50 41 59  |S/ENC.445452.PAY|
00000040  41 42 4c 45 53 09 34 33  35 36 00 41 43 43 4f 4d  |ABLES.4356.ACCOM|

# Using the `tr` utility, we can map \0 to newline
# in order to display the output on the console:
sh$ paste -z *.zero | tr '\0' '\n' | head -3
ACCOUNTLIB    ACCOUNTNUM
TIDE SCHEDULE    623477
VAT BS/ENC    445452

Étant donné que mes fichiers d'entrée ne contiennent pas de nouvelles lignes intégrées dans les données, le -z option est d'une utilité limitée ici. Mais sur la base des explications ci-dessus, je vous laisse essayer de comprendre pourquoi l'exemple suivant fonctionne "comme prévu". Pour bien comprendre que vous devez probablement télécharger les exemples de fichiers et les examiner au niveau de l'octet à l'aide du hexdump utilitaire comme nous l'avons fait ci-dessus :

# Somehow, the head utility seems to be confused
# by the ACCOUNTS file content (I wonder why?;)
sh$ head -3 CATEGORIES ACCOUNTS
==> CATEGORIES <==
PRIVATE
ACCOMMODATION GUIDE
SHARED

==> ACCOUNTS <==
6233726230846265106159126579914356613866618193623477623795445333445452605751
# The output is quite satisfactory, putting the account number
# after the account name and keeping things surprisingly nicely formatted:
sh$ paste -z -d':' CATEGORIES ACCOUNTS | tr '\0' '\n' | head -5
PRIVATE
ACCOMMODATION GUIDE:623372

SHARED
ADVERTISEMENTS:623084

Quoi de plus ?

Le paste La commande produit uniquement une sortie de texte délimité. Mais comme illustré à la fin de la vidéo d'introduction, si votre système prend en charge la column BSD utilitaire, vous pouvez l'utiliser pour obtenir des tableaux bien formatés en convertissant le paste la sortie de la commande dans un format de texte à largeur fixe. Mais cela fera l'objet d'un prochain article. Alors restez à l'écoute et, comme toujours, n'oubliez pas de partager cet article sur vos sites Web et réseaux sociaux préférés !


Linux
  1. Commande Linux Cat :utilisation et exemples

  2. La commande Linux Sed :utilisation et exemples

  3. Commandes Linux :jobs, bg et fg

  4. La commande Linux AWK - Exemples de syntaxe d'utilisation Linux et Unix

  5. Commande Linux df

50 commandes grep productives et pratiques pour les passionnés de Linux

16 exemples pratiques et utiles de la commande Echo sous Linux

15 exemples pratiques de commande Rsync sous Linux

5 exemples pratiques de la commande Tail sous Linux

7 Utilisation essentielle et pratique de la commande Coller sous Linux

Commande Cat sous Linux :Exemples essentiels et avancés