Sans en utilisant sed
ou awk
, seulement cut
, comment obtenir le dernier champ lorsque le nombre de champs est inconnu ou change à chaque ligne?
Vous pouvez essayer quelque chose comme ça:
echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev
Explication
moc.elgoog.spam
cut
utilise point comme délimiteur et choisit le premier champ, qui est moc
com
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.
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.
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)
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.
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.
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
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
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 '|' '/'
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.
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