Jai besoin daide pour comprendre comment utiliser la commande sed pour nafficher que la première colonne et la dernière colonne dun fichier texte. Voici ce que jai jusquà présent pour la colonne 1:
cat logfile | sed "s/\|/ /"|awk "{print $1}"
Ma faible tentative pour afficher également la dernière colonne a été:
cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}"
Cependant, cela prend la première colonne et la dernière colonne et les fusionne dans une liste. Existe-t-il un moyen dimprimer clairement la première colonne et les dernières colonnes avec les commandes sed et awk?
Exemple dentrée:
foo|dog|cat|mouse|lion|ox|tiger|bar
Commentaires
- Veuillez fournir un exemple d’entrée.
Réponse
Presque là. Mettez simplement les deux références de colonne lune à côté de lautre.
cat logfile | sed "s/|/ /" | awk "{print $1, $8}"
Notez également que vous navez pas besoin de cat
ici .
sed "s/|/ /" logfile | awk "{print $1, $8}"
Notez également que vous pouvez indiquer à awk
que les séparateurs de colonnes sont |
, au lieu de blancs, vous navez donc pas besoin de sed
non plus.
awk -F "|" "{print $1, $8}" logfile
Selon les suggestions de Caleb , si vous voulez une solution qui affiche toujours le dernier champ , même sil ny en a pas exactement huit, vous pouvez utiliser $NF
.
awk -F "|" "{print $1, $NF}" logfile
Aussi, si vous voulez le sortie pour conserver les séparateurs |
, au lieu dutiliser un espace, vous pouvez spécifier les séparateurs de champ de sortie. Malheureusement, cest un peu plus maladroit que dutiliser simplement lindicateur -F
, mais voici trois approches.
-
Vous pouvez affecter lentrée et les séparateurs de champ de sortie dans
awk
lui-même, dans le bloc BEGIN.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile
-
Vous pouvez affecter ces variables lors de lappel de
awk
depuis la ligne de commande, via lindicateur-v
.awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile
-
ou simplement:
awk -F "|" "{print $1 "|" $8}" logfile
Commentaires
- Bon travail pour expliquer comment ce problème peut être simplifié. Vous pouvez ajouter une note expliquant comment utiliser
|
comme séparateur de sortie au lieu de lespace par défaut pour la concaténation de chaînes. Vous pouvez également expliquer lutilisation de$NF
au lieu du codage en dur$8
pour obtenir la dernière colonne. - ensuite comment mettre à jour le fichier?
- @pankajprasad Écrire dans un nouveau fichier avec h
>
puis écrasez lancien ou utilisezsponge
. Cest vraiment une nouvelle question. - @Sparhawk ça marche, mais le contenu de lalésage est effacé. comment gérer cela?
- @pankajprasad Vous devez poser une nouvelle question. Cliquez sur le gros bouton bleu en haut qui dit » Poser la question « .
Réponse
Vous utilisez quand même awk
:
awk "{ print $1, $NF }" file
Commentaires
- wouldn ‘ t vous devez spécifier le séparateur de champ de saisie (car dans ce cas il semble être
|
plutôt que lespace) avec-F\|
ou similaire? Et sil voulait utiliser le même délimiteur pour la sortie? - @Caleb Probablement: jattendais que lOP confirme à quoi exactement lentrée ressemblait, plutôt que dessayer de estimation basée sur les exemples qui ne fonctionnent pas …
- Notez que cela suppose que lentrée contient au moins 2 champs.
- @St é phaneChazelas OP a clairement indiqué dans le code quil a toujours huit champs.
- @ michaelb958 Je pense » clairement » surestime le cas, juste un peu 🙂
Réponse
Remplacez simplement du premier au dernier |
avec un |
(ou un espace si vous préférez):
sed "s/|.*|/|/"
Notez que même sil ny a « pas dimplémentation sed
où |
est spécial (tant que étendu régulier les expressions ne sont pas activées via -E
ou dans certaines implémentations), \|
lui-même est spécial dans certains comme GNU sed
. Vous ne devez donc pas échapper à |
si vous voulez qu’il corresponde au caractère |
.
Si vous remplacez par un espace et si lentrée peut déjà contenir des lignes avec un seul |
, alors, vous « devrez traiter cela spécialement comme |.*|
ne correspondra pas à ceux-ci.Cela pourrait être:
sed "s/|\(.*|\)\{0,1\}/ /"
(cest-à-dire rendre la partie .*|
facultative) Ou:
sed "s/|.*|/ /;s/|/ /"
ou:
sed "s/\([^|]*\).*|/\1 /"
Si vous voulez les premier et huitième champs quel que soit le nombre de champs dans lentrée, alors cest juste:
cut -d"|" -f1,8
(tout cela fonctionnerait avec nimporte quel utilitaire compatible POSIX en supposant lentrée forme du texte valide (en particulier, les sed
ne fonctionneront généralement pas si lentrée contient des octets ou des séquences doctets qui ne forment pas de caractères valides dans la locale actuelle comme par exemple printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/"
dans un environnement local UTF-8)).
Réponse
Si vous vous trouvez sans problèmes et sans sed, vous pouvez atteindre le même chose avec coreutils:
paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev)
Commentaires
-
cut
est plus propre et plus compact que awk / sed lorsque vous êtes simplement intéressé par la première colonne, ou si les délimiteurs sont fixes (cest-à-dire pas un nombre variable despaces). - Assez élégant!
Réponse
Il semble que vous essayiez dobtenir le premier et le dernier champs de texte délimités par |
.
Jai supposé que votre fichier journal contenait le texte comme ci-dessous,
foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo
Et vous voulez la sortie comme,
foo bar bar foo
Si oui, alors voici la commande pour vos « s
Via GNU sed,
sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file
Exemple:
$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar
Commentaires
- Les colonnes ne sont pas délimitées par un tube | mais ils sont en colonnes, je suis intéressé à utiliser sed mais pas à utiliser la commande awk comme vous lavez fait dans votre commande: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ file
- » Les colonnes sont non délimité par un tuyau | mais ils sont dans les colonnes « , vous voulez dire que les colonnes sont séparées par des espaces?
- Un exemple dentrée et une sortie seraient mieux.
Réponse
Vous devriez probablement le faire avec sed
– je le ferais de toute façon – mais, juste car personne na encore écrit celui-ci:
while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT
OUTPUT
foo | bar