web-dev-qa-db-fra.com

Comment trouver le dernier champ en utilisant 'cut'

Sans en utilisant sed ou awk, seulement cut, comment obtenir le dernier champ lorsque le nombre de champs est inconnu ou change à chaque ligne?

204
noobcoder

Vous pouvez essayer quelque chose comme ça:

echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev

Explication

  • l'inverse de maps.google.com sera moc.elgoog.spam
  • cut utilise point comme délimiteur et choisit le premier champ, qui est moc
  • enfin, nous inversons à nouveau (merci pour le rappel, @tom) pour obtenir com
472
zedfoxus

Utilisez une extension de paramètre. Ceci est beaucoup plus efficace que n'importe quel type de commande externe, cut (ou grep) incluse.

data=foo,bar,baz,qux
last=${data##*,}

Voir BashFAQ # 100 pour une introduction à la manipulation de chaîne native dans bash.

99
Charles Duffy

Il n’est pas possible d’utiliser simplement cut. Voici un moyen d'utiliser grep:

grep -o '[^,]*$'

Remplacez la virgule pour les autres délimiteurs.

67
tom

Sans awk? ... Mais c'est si simple avec awk:

echo 'maps.google.com' | awk -F. '{print $NF}'

AWK est un outil beaucoup plus puissant à avoir dans votre poche .- F si pour séparateur de champsNF est le nombre de champs (correspond également à l'index du dernier)

18
Amir Mehler

Il y a plusieurs façons. Vous pouvez aussi utiliser ceci.

echo "Your string here"| tr ' ' '\n' | tail -n1
> here

Évidemment, l’espace vide pour la commande tr doit être remplacé par le délimiteur dont vous avez besoin.

12
rjni

C’est la seule solution possible pour n’utiliser que couper:

echo "s.t.r.i.n.g." | coupé-d '.' -f2 - [repeat_following_part_forever_or_until_out_of_memory:] | coupé-d '.' -f2-

En utilisant cette solution, le nombre de champs peut en effet être inconnu et varier de temps en temps. Cependant, comme la longueur de ligne ne doit pas dépasser les caractères LINE_MAX ou les champs, y compris le caractère de nouvelle ligne, un nombre arbitraire de champs ne peut jamais faire partie d'une condition réelle de cette solution.

Oui, une solution très stupide mais la seule qui répond aux critères, je pense.

6
A friend

implémentation suivante suggestion d'un ami

#!/bin/bash
rcut(){

  nu="$( echo $1 | cut -d"$DELIM" -f 2-  )"
  if [ "$nu" != "$1" ]
  then
    rcut "$nu"
  else
    echo "$nu"
  fi
}

$ export DELIM=.
$ rcut a.b.c.d
d
2
user2166700

Si vous avez un fichier nommé filelist.txt, il s'agit d'une liste de chemins d'accès tels que: C: /dir1/dir2/file1.h C.

alors vous pouvez faire ceci: rev filelist.txt | cut -d "/" -f1 | tour

0
aperson1961

Si votre chaîne d'entrée ne contient pas de barres obliques, vous pouvez utiliser basename et un sous-shell:

$ basename "$(echo 'maps.google.com' | tr '.' '/')"

Ceci n'utilise pas sed ou awk, mais n'utilise pas non plus cut non plus, donc je ne suis pas tout à fait sûr qu'il s'agisse d'une réponse à la question dans sa formulation.

Cela ne fonctionne pas bien si le traitement des chaînes d'entrée pouvant contenir des barres obliques. Une solution de contournement à cette situation consisterait à remplacer la barre oblique par un autre caractère dont vous savez qu'il ne fait pas partie d'une chaîne d'entrée valide. Par exemple, le caractère pipe (|) n'est pas autorisé non plus dans les noms de fichiers, cela fonctionnerait donc:

$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'
0
jstine

Ajouter une approche à cette vieille question juste pour le plaisir:

$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info

$ cat tmp.sh # showing off the script to do the job
#!/bin/bash
delim=';'
while read -r line; do  
    while [[ "$line" =~ "$delim" ]]; do
        line=$(cut -d"$delim" -f 2- <<<"$line")
    done
    echo "$line"
done < input.file

$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info

En plus de bash, seule la coupe est utilisée. Eh bien, et écho, je suppose.

0
Kaffe Myers

J'ai réalisé que si nous nous assurions simplement qu'un délimiteur de fin existe, cela fonctionne. Donc, dans mon cas, j'ai des délimiteurs par virgule et par des espaces. J'ajoute un espace à la fin; $ ans="a, b" $ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2 b

0
AnneTheAgile