Comment est-ce que je coupe les espaces de début et de fin de chaque ligne d'une sortie?

155

Je voudrais supprimer tous les espaces et les tabulations de début et de fin de chaque ligne dans une sortie.

Existe-t-il un outil simple dans lequel trimje pourrais canaliser ma sortie?

Exemple de fichier:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 
rubo77
la source
1
Pour ceux qui recherchent ici une solution pour supprimer les nouvelles lignes, le problème est différent. Par définition, une nouvelle ligne crée une nouvelle ligne de texte. Par conséquent, une ligne de texte ne peut pas contenir de nouvelle ligne. La question que vous voulez poser est la suivante: comment supprimer une nouvelle ligne du début ou de la fin d'une chaîne: stackoverflow.com/questions/369758 ou comment supprimer des lignes vides ou des lignes ne contenant
Tony

Réponses:

201
awk '{$1=$1;print}'

ou plus court:

awk '{$1=$1};1'

Souhaitez-vous couper l'espace de début et de fin ou les caractères de tabulation 1 et aussi presser des séquences de tabulations et d'espaces dans un seul espace.

Cela fonctionne parce que lorsque vous affectez quelque chose à l’un des champs , awkreconstruit l’enregistrement complet (tel qu’imprimé par print) en joignant tous les champs ( $1, ..., $NF) avec OFS(espace par défaut).

1 (et éventuellement d'autres caractères vides en fonction des paramètres régionaux et de la awkmise en œuvre)

Stéphane Chazelas
la source
2
Le point-virgule du deuxième exemple est superflu. Pourrait utiliser:awk '{$1=$1}1'
Brian
Intéressant ... Aucun point-virgule n'est pris en charge par gawk, mawk et awk d'OS X. (Au moins pour mes versions (1.2, 4.1.1 et 20070501, respectivement))
Brian
1
La seule chose que je n'aime pas dans cette approche, c'est que vous perdez des espaces répétés dans la ligne. Par exemple,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly
2
echo ' hello ' | xargs
JREAM
44

La commande peut être condensée comme si vous utilisiez GNU sed:

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

Exemple

Voici la commande ci-dessus en action.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

Vous pouvez utiliser hexdumppour confirmer que la sedcommande supprime correctement les caractères souhaités.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

Cours de caractère

Vous pouvez également utiliser des noms de classe de caractères au lieu de lister littéralement les ensembles de la manière suivante [ \t]:

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

Exemple

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

La plupart des outils GNU utilisant des expressions régulières (regex) prennent en charge ces classes.

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

Utiliser ces jeux au lieu de jeux littéraux semble toujours un gaspillage d’espace, mais si vous souhaitez que votre code soit portable ou que vous ayez à traiter avec des jeux de caractères différents (think international), vous voudrez probablement utiliser les noms de classe. au lieu.

Références

slm
la source
Notez que cela [[:space:]]n’est pas équivalent à [ \t]dans le cas général (unicode, etc.). [[:space:]]sera probablement beaucoup plus lent (car il y a beaucoup plus de types d'espaces dans unicode que juste ' 'et '\t'). Même chose pour tous les autres.
Olivier Dulac
sed 's/^[ \t]*//'n'est pas portable. Finalement, POSIX exige même de supprimer une séquence d’espace, une barre oblique inverse ou des tcaractères, et c’est ce que GNU fait sedégalement POSIXLY_CORRECTdans l’environnement.
Stéphane Chazelas
Et si je veux couper les caractères de nouvelle ligne? '\ n \ n text \ n \ n'
Eugene Biryukov
J'aime la solution sed en raison de l'absence d'autres effets secondaires, comme dans la solution awk. La première variante ne fonctionne pas lorsque je l'ai essayé sous bash sur OSX juste maintenant, mais la version de la classe de caractères fonctionne:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony
@EugeneBiryukov voir mon commentaire sur le post original
Tony
23

Comme suggéré par Stéphane Chazelas dans la réponse acceptée, vous pouvez maintenant
créer un script /usr/local/bin/trim:

#!/bin/bash
awk '{$1=$1};1'

et donnez à ce fichier les droits exécutables:

chmod +x /usr/local/bin/trim

Maintenant, vous pouvez passer chaque sortie à trimpar exemple:

cat file | trim

(pour les commentaires ci-dessous: je l'ai déjà utilisé: while read i; do echo "$i"; done
ce qui fonctionne aussi très bien, mais est moins performant)

rubo77
la source
1
Bonne chance si votre fichier est énorme et / ou contient des barres obliques inverses.
don_crissti
1
@don_crissti: pourriez-vous en dire un peu plus? Quelle solution conviendrait le mieux pour des fichiers volumineux, et comment pourrais-je modifier ma solution si le fichier contenait des barres obliques inverses?
rubo77
3
Vous devrez utiliser while read -r linepour préserver antislashs et encore ... . En ce qui concerne les fichiers volumineux / la vitesse, vous avez vraiment choisi la pire solution. Je ne pense pas qu'il y ait pire. Voir les réponses dans Pourquoi utiliser une boucle shell pour traiter du texte une mauvaise pratique? y compris mon commentaire sur la dernière réponse où j'ai ajouté un lien à un repère de vitesse. Les sedréponses ici sont parfaitement bien IMO et bien mieux que read.
don_crissti
@don_crissti ... et / ou comporte des lignes commençant par -et suivies d'une combinaison de 1 ou plusieurs caractères e, E ou n, et / ou contenant des caractères NUL. En outre, une ligne non terminée après la dernière nouvelle ligne sera ignorée.
Stéphane Chazelas
1
Vous pouvez également ajouter un alias dans / etc / profile (ou votre ~ / .bashrc ou ~ / .zshrc etc ...) alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton
22

xargs sans arguments le fait.

Exemple:

trimmed_string=$(echo "no_trimmed_string" | xargs) 
Newton_Jose
la source
1
Ceci contracte également plusieurs espaces dans une ligne, ce qui n’était pas demandé dans la question
roaima le
1
@roaima - vrai, mais la réponse acceptée réduit également les espaces (ce qui n'était pas demandé dans la question). Je pense que le vrai problème ici est que xargscela échouera si l'entrée contient des barres obliques inverses et des guillemets simples.
don_crissti
@don_crissti, cela ne signifie pas que la réponse acceptée réponde correctement à la question telle qu'elle a été posée. Mais dans ce cas, ici, cela n’a pas été signalé comme une mise en garde, contrairement à la réponse acceptée. J'espère que j'ai souligné le fait au cas où cela serait pertinent pour un futur lecteur.
Roaima
Il saute également sur les guillemets simples, les guillemets doubles, les caractères de barre oblique inverse. Il exécute également une ou plusieurs echoinvocations. Certaines implémentations d'écho traiteront également les options et / ou les barres obliques inverses ... Cela ne fonctionne également que pour une entrée sur une seule ligne.
Stéphane Chazelas
17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Si vous lisez une ligne dans une variable shell, le faites-vous readdéjà sauf instruction contraire .

Gilles
la source
1
+1 pour read. Donc, si vous continuez à lire, cela fonctionne:cat file | while read i; do echo $i; done
rubo77
1
@rubo sauf que dans votre exemple, la variable non citée est également retraitée par le shell. Utilisez echo "$i"pour voir le véritable effet de laread
roaima
13

Si vous stockez des lignes en tant que variables, vous pouvez utiliser bash pour effectuer le travail:

supprime les espaces de début d'une chaîne:

shopt -s extglob
echo ${text##+([[:space:]])}

supprime les espaces de fin d'une chaîne:

shopt -s extglob
echo ${text%%+([[:space:]])}

supprime tous les espaces d'une chaîne:

echo ${text//[[:space:]]}
Łukasz Rajchel
la source
La suppression de tous les espaces d'une chaîne n'est pas la même chose que la suppression des espaces de début et de fin (comme dans la question).
Catpnose
De loin la meilleure solution - elle ne nécessite que des commandes intégrées à bash et aucun processus externe.
user259412
2
Agréable. Les scripts s'exécutent BEAUCOUP plus rapidement s'ils ne doivent pas intégrer des programmes extérieurs (tels que awk ou sed). Cela fonctionne aussi avec les versions "modernes" (93u +) de ksh.
user1683793
9

Pour supprimer tous les espaces de début et de fin d'une ligne donnée à l'aide d'un outil «canalisé», je peux identifier 3 manières différentes qui ne sont pas complètement équivalentes. Ces différences concernent les espaces entre les mots de la ligne de saisie. En fonction du comportement attendu, vous ferez votre choix.

Exemples

Pour expliquer les différences, considérons cette ligne de saisie factice:

"   \t  A   \tB\tC   \t  "

tr

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

trest vraiment une commande simple. Dans ce cas, il supprime tout espace ou caractère de tabulation.

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk supprime les espaces de début et de fin et réduit en un espace unique chaque espace entre les mots.

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

Dans ce cas, sedsupprime les espaces de début et de fin sans toucher les espaces entre les mots.

Remarque:

Dans le cas d'un mot par ligne, trfait le travail.

Frozar
la source
Rien de tout cela n'élimine les nouvelles lignes de fuite / principales
entretien
+1 pour une liste de solutions avec leur sortie (parfois inattendue).
Tony
@ user61382 c'est assez tard, mais voir mon commentaire sur le post original.
Tony
@highmaintenance: utilisez [:space:], au lieu de [: blank:], pour la commande tr, comme:: ... | tr -d [:space:], supprimer également les nouvelles lignes. (voir: man tr)
tron5
6

sed est un excellent outil pour cela:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

Vous pouvez l’utiliser pour votre cas soit en lisant le texte, par exemple

<file sed -e 's/^[[...

ou en agissant dessus 'inline' si vous sedêtes GNU:

sed -i 's/...' file

Mais changer le code source de cette manière est "dangereux", car il peut être irrécupérable s’il ne fonctionne pas correctement (ou même quand cela fonctionne!), faites donc une sauvegarde en premier (ou utilisez-en un -i.bakqui présente également l’avantage d’être portable sur certains BSD sed). !

Michael Durrant
la source
2

traduire la commande fonctionnerait

cat file | tr -d [:blank:]
Srinagesh
la source
4
Cette commande est incorrecte car elle supprime tous les espaces du fichier, pas seulement les espaces de début / fin.
Brian Redbeard
@BrianRedbeard Vous avez raison. C'est toujours une réponse utile pour une chaîne monolithique, sans espaces.
Anthony Rutledge
0

Si la chaîne que vous essayez d'ajuster est courte et continue / contiguë, vous pouvez simplement la transmettre en tant que paramètre à n'importe quelle fonction bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Subrata Das
la source