Senza usando sed
o awk
, only cut
, come faccio ad ottenere l'ultimo campo quando il numero di campi è sconosciuto o cambia ad ogni linea?
Potresti provare qualcosa come questo:
echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev
Spiegazione
moc.elgoog.spam
cut
utilizza punto come delimitatore e sceglie il primo campo, che è moc
com
Utilizzare un parametro di espansione. Questo è molto più efficiente di qualsiasi tipo di comando esterno, cut
(o grep
) incluso.
data=foo,bar,baz,qux
last=${data##*,}
Vedi BashFAQ # 100 per un'introduzione alla manipolazione nativa delle stringhe in bash.
Non è possibile usare solo cut
. Ecco un modo per usare grep
:
grep -o '[^,]*$'
Sostituisci la virgola per altri delimitatori.
Senza awk? ... Ma è così semplice con awk:
echo 'maps.google.com' | awk -F. '{print $NF}'
AWK è uno strumento molto più potente da avere in tasca .- F se per il campo separatorNF è il numero di campi (indica anche l'indice dell'ultimo)
Ci sono molti modi. Puoi usare anche questo.
echo "Your string here"| tr ' ' '\n' | tail -n1
> here
Ovviamente, l'input dello spazio vuoto per il comando tr deve essere sostituito con il delimitatore di cui hai bisogno.
Questa è l'unica soluzione possibile per l'utilizzo di nient'altro che tagliare:
echo "s.t.r.i.n.g." | taglia -d '.' -f2 - [repeat_following_part_forever_or_until_out_of_memory:] | taglia -d '.' -f2-
Usando questa soluzione, il numero di campi può effettivamente essere sconosciuto e variare di volta in volta. Tuttavia, poiché la lunghezza della linea non deve superare i caratteri oi campi LINE_MAX, incluso il carattere di nuova riga, un numero arbitrario di campi non può mai essere parte come una condizione reale di questa soluzione.
Sì, una soluzione molto sciocca ma l'unica che soddisfa i criteri che penso.
i seguenti strumenti Suggerimento di un amico
#!/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
Se si dispone di un file denominato filelist.txt che è un elenco percorsi come il seguente: C: /dir1/dir2/file1.h C: /dir1/dir2/dir3/file2.h
allora puoi fare questo: rev filelist.txt | cut -d "/" -f1 | rev
Se la stringa di input non contiene barre, puoi usare basename
e una subshell:
$ basename "$(echo 'maps.google.com' | tr '.' '/')"
Questo non usa sed
o awk
ma non usa neanche cut
, quindi non sono abbastanza sicuro se si qualifica come risposta alla domanda come formulata.
Questo non funziona bene se si elaborano stringhe di input che possono contenere barre in avanti. Una soluzione alternativa per quella situazione sarebbe quella di sostituire la barra in avanti con qualche altro carattere che, sai, non fa parte di una stringa di input valida. Ad esempio, il carattere pipe (|
) non è consentito nei nomi dei file, quindi funzionerebbe:
$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'
Aggiungere un approccio a questa vecchia domanda solo per il gusto di farlo:
$ 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
Oltre a bash, viene utilizzato solo il taglio. Bene, ed eco, immagino.
Mi sono reso conto che se solo ci accertiamo che esista un delimitatore finale, funziona. Quindi nel mio caso ho delimitatori di virgola e spazi bianchi. Aggiungo uno spazio alla fine;
$ ans="a, b"
$ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2
b