faire une sortie grep sans retour à la ligne

8

Veuillez considérer cet extrait:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')

Je veux mettre le dernier mot dans une variable si une condition de modèle correspond aux lignes d'un fichier texte arbitraire

Mon problème est que la variable Xa CR ou LF ou CRLF à la fin, selon le fichier source, dont je veux me débarrasser, car cela interfère avec une opération ultérieure que j'ai l'intention de faire.
J'ai même essayé quelque chose comme:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* \([A-Za-z]\+\)/\1/p')

s'attendant donc à ce que la sedsortie soit limitée, [A-Za-z]+mais il y a toujours ces octets gênants à l'intérieur de la variable X.

Comment puis - je me débarrasser, sans utiliser trop de code comme voir ce que les octets sont à la fin avec xxdpuis cutet des complications similaires?

zetah
la source

Réponses:

4

Il semble que ce awkserait un meilleur choix pour vos besoins, car ces problèmes n'existent pas car il peut utiliser des champs et des enregistrements:

x=$(awk '/some-pattern/ { sub(/\r$/, "") ; printf("%s", $NF) ; exit }' some-file)

La substitution évite votre problème avec les fins de ligne CRLF.

sub(/\r$/, "")supprime le CR de fin, s'il existe. Comme awktraite \ncomme séparateur enregistrement (ligne), vous ne avez pas besoin de dépouiller, car il est pas dans les données examinées.

printf("%s", $NF)affiche le champ final ( $NF) sans retour à la ligne ( printet certaines autres awkfonctions ajoutent un retour à la ligne par défaut).

exitse produit après les deux premières actions - c'est l'équivalent de m1dans votre grepligne de commande. Cela garantit que les awksorties après l'exécution des deux commandes précédentes - et puisque ces commandes sont émises lors d'une correspondance, et awk évalue les données d'une manière FIFO, cela n'imprimera que la première correspondance.

Chris Down
la source
Merci, il a l'air élégant mais malheureusement CRLF est toujours à l'intérieurX
zetah
:) Maintenant, il n'a plus l'air élégant et ce n'est toujours pas bon
zetah
@zetah - Il n'y en aura pas CR, mais il y en aura un LF. J'ai eu du mal à comprendre ce que vous voulez de la question, j'espère que mon montage fait ce que vous voulez.
Chris Down
OK, cette fois, ça fait du bien - sortir le dernier mot d'une ligne si cette ligne satisfait une condition de modèle - je ne sais pas, c'est peut-être clair pour moi parce que j'ai ce problème, puis difficile à expliquer en tant que locuteur anglais non natif . Quoi qu'il en soit, j'attendrai un peu plus si quelqu'un aborde cela avec une grep/sedsolution à la place awk(que je ne comprends pas), sinon je l'utilise. Merci
Zetah
@zetah - Je vais ajouter une explication pour que vous puissiez mieux la comprendre, une seconde.
Chris Down
7

Le ``ou $()supprimera la nouvelle ligne de la fin, mais pour le faire par programme, utilisez tr.

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\012\015'

Cela supprimera le retour chariot et / ou la nouvelle ligne de la chaîne.

Quel pourrait être le problème est de savoir comment vous sortez ensuite le résultat. Par exemple, par défaut, echoajoute une nouvelle ligne. Vous pouvez utiliser echo -nou printf.

Arcege
la source
Cela supprimera également les retours chariot qui peuvent se produire dans la chaîne, ce qui peut ne pas être souhaité.
Chris Down
Oui, bien qu'il soit possible d'avoir un retour chariot intégré dans une seule ligne, c'est extrêmement rare. La -m1veillerai à ce qu'il n'y a qu'une seule sortie ligne, qui , selon toute vraisemblance, aurait le retour chariot à la fin.
Arcege
ah tr... intéressant, fonctionne à la fois sur les fichiers LF et CRLF. Je pense que \010\013pour une raison quelconque, et \f\rfonctionne également correctement. À propos du résultat: je ne mets pas réellement la sortie en variable mais en tant que variable enfermée $()dans le modèle pour grepmatch - some pipe | grep -o " $(...) ". Merci pour les commentaires
zetah
3

Je préfère cette façon

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\n'
Steven Penny
la source
2

Cela fonctionne pour moi:

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d "\n" | tr -d "\r"
Funky_Pandy
la source
0

Pourquoi ne pas simplement laisser sedfaire le [\r\f]nettoyage:

# using Bash's $'string' idiom (that decodes ANSI C escape sequences)
# cf. http://wiki.bash-hackers.org/syntax/quoting#ansi_c_like_strings
- X="$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')"
+ X="$(grep -m1 'some-pattern' some-file | sed -n -e $'s/[\r\f]*$//' -e 's/.* //p')"

Votre deuxième approche n'a pas de regex finale pour attraper le CR de fuite, \r.

# sample code to remove trailing \r with sed
# cf. http://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)/\1/p' | od -c
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)[[:space:]]*/\1/p' | od -c

# keeps trailing space after c
printf 'a b c \r' | sed -n 's/^.* \([[:alpha:] ]\{1,\}\)[[:space:]]*/\1/p' | od -b
tchad
la source
0

La version normale de grep (y compris grep -P) sort toujours un saut de ligne avec sa correspondance, donc si vous n'avez qu'un seul résultat (ou si vous voulez seulement que le saut de ligne ajouté final soit supprimé), il suffit de supprimer simplement le caractère final de la sortie, ce que vous pouvez faire en le canalisant head -c-1.

Jon
la source