web-dev-qa-db-fra.com

Comment utiliser une commande Shell pour afficher uniquement la première colonne et la dernière colonne dans un fichier texte?

J'ai besoin d'aide pour comprendre comment utiliser la commande sed pour n'afficher que la première et la dernière colonne d'un fichier texte. Voici ce que j'ai jusqu'à présent pour la colonne 1:

cat logfile | sed 's/\|/ /'|awk '{print $1}'

Ma faible tentative pour que la dernière colonne s'affiche également était:

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 d'imprimer clairement la première et la dernière colonnes avec les commandes sed et awk?

Exemple d'entrée:

foo|dog|cat|mouse|lion|ox|tiger|bar
39
user70573

Presque là. Placez simplement les deux références de colonne l'une à côté de l'autre.

cat logfile | sed 's/|/ /' | awk '{print $1, $8}'

Notez également que vous n'avez pas besoin de cat ici.

sed 's/|/ /' logfile | awk '{print $1, $8}'

Notez également que vous pouvez dire à awk que les séparateurs de colonnes sont |, au lieu de blancs, vous n'avez donc pas besoin de sed non plus.

awk -F '|' '{print $1, $8}' logfile

Selon suggestions par Caleb , si vous voulez une solution qui génère toujours le dernier champ, même s'il n'y en a pas exactement huit, vous pouvez utiliser $NF.

awk -F '|' '{print $1, $NF}' logfile

De plus, si vous souhaitez que la sortie conserve le | séparateurs, au lieu d'utiliser un espace, vous pouvez spécifier les séparateurs de champ de sortie. Malheureusement, c'est un peu plus maladroit que d'utiliser simplement le -F flag, mais voici trois approches.

  • Vous pouvez affecter les séparateurs de champs d'entrée et 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 l'appel de awk depuis la ligne de commande, via le -v drapeau.

    awk -v 'FS=|' -v 'OFS=|' '{print $1, $8}' logfile
    
  • ou simplement:

    awk -F '|' '{print $1 "|" $8}' logfile
    
61
Sparhawk

Vous utilisez quand même awk:

awk '{ print $1, $NF }' file
14
jasonwryan

Remplacez simplement du premier au dernier | avec un | (ou espace si vous préférez):

sed 's/|.*|/|/'

Notez que bien qu'il n'y ait pas d'implémentation de sed| est spécial (tant que étend les expressions régulières ne sont pas activées via -E ou -r dans certaines implémentations), \| lui-même est spécial dans certains comme GNU sed. Vous devriez donc pas échapper | si vous voulez qu'il corresponde au | personnage.

Si le remplacement par un espace et si l'entré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\}/ /'

(c'est-à-dire faire le .*| 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 l'entrée, alors c'est juste:

cut -d'|' -f1,8


(tous ceux-ci fonctionneraient avec n'importe quel utilitaire compatible POSIX en supposant que le texte d'entrée des formulaires est valide (en particulier, les sed ne fonctionneront généralement pas si l'entrée contient des octets ou des séquences d'octets qui ne forment pas de caractères valides dans le locale actuelle comme par exemple printf 'unix|St\351phane|Chazelas\n' | sed 's/|.*|/|/' dans un environnement local UTF-8)).

14
Stéphane Chazelas

Si vous vous retrouvez sans gêne ni séduction, vous pouvez réaliser la même chose avec coreutils:

paste <(           cut -d'|' -f1  file) \ 
      <(rev file | cut -d'|' -f1 | rev)
5
Thor

Il semble que vous essayez d'obtenir les premier et dernier champs de texte délimités par |.

J'ai supposé que votre fichier journal contient le texte 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 la vôtre

Par 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
2
Avinash Raj

Vous devriez probablement le faire avec sed - je le ferais quand même - mais, juste parce que personne n'a 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

PRODUCTION

     foo | bar
1
mikeserv