Antworten:
Verwenden Sie cut
mit _
als Feldtrennzeichen und erhalten gewünschten Felder:
A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
Sie können echo
anstelle des Here-Strings auch and pipe verwenden:
A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
Beispiel:
$ s='one_two_three_four_five'
$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two
$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
$ echo $FILE
my_user/my_folder/file.csv
$ A="$(cut -d'/' -f2 <<<"$FILE")"
$ echo $A
[file]*
Wissen Sie, was hier passiert?
echo "${s##*_}"
Mit nur POSIX sh Konstrukten, können Sie Parameter Substitution baut einen Begrenzer zu einem Zeitpunkt , zu analysieren. Beachten Sie, dass dieser Code davon ausgeht, dass die erforderliche Anzahl von Feldern vorhanden ist, andernfalls wird das letzte Feld wiederholt.
string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"
Alternativ können Sie eine nicht in Anführungszeichen gesetzte Parametersubstitution mit deaktivierter Platzhaltererweiterung verwenden und IFS
das Trennzeichen verwenden (dies funktioniert nur, wenn das Trennzeichen ein einzelnes Zeichen ohne Leerzeichen ist oder wenn eine Leerzeichenfolge ein Trennzeichen ist).
string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
Dadurch werden die Positionsparameter überlastet. Wenn Sie dies in einer Funktion tun, sind nur die Positionsparameter der Funktion betroffen.
Ein weiterer Ansatz ist die Verwendung des read
eingebauten.
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
unset IFS
kehrt nicht IFS
zum Standard zurück. Wenn danach jemand OldIFS="$IFS"
einen Nullwert in OldIFS hat. Außerdem wird davon ausgegangen, dass der vorherige Wert von IFS der Standardwert ist, was durchaus möglich (und sinnvoll) ist, nicht zu sein. Die einzig richtige Lösung ist das Speichern old="$IFS"
und spätere Wiederherstellen mit IFS = "$ old". Oder ... eine Unterschale verwenden (...)
. Oder besser noch, lies meine Antwort.
unset IFS
wird nicht IFS
auf den Standardwert zurückgesetzt, aber die Feldaufteilung wird auf den Standardeffekt zurückgesetzt. Ja, dies ist eine Einschränkung, in der Praxis jedoch in der Regel akzeptabel. Das Problem mit einer Subshell ist, dass wir Daten daraus holen müssen. Ich zeige eine Lösung, die den Zustand am Ende nicht ändert, mit read
. (Es funktioniert in POSIX-Shells, aber IIRC nicht in der Bourne-Shell, da es read
aufgrund des Here-Dokuments in einer Subshell ausgeführt werden würde .) Die Verwendung von <<<
as in you answer ist eine Variante, die nur in ksh / bash / zsh funktioniert.
user/my_folder/[this_is_my_file]*
? Was ich erhalte, wenn ich diesen Schritten folge, ist[this_is_my_file]*
/
.
Wollte eine awk
Antwort sehen, also hier ist eine:
A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
awk -F_ '{print $NF}' <<< 'one_two_3_4_five'
Der einfachste Weg (für Shells mit <<<) ist:
IFS='_' read -r a second a fourth a <<<"$string"
Verwenden einer temporalen Variablen, $a
anstatt sich über $_
eine Shell zu beschweren.
In einem vollständigen Skript:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<<"$string"
echo "$second $fourth"
Keine Änderung des IFS, keine Probleme mit set -f
(Pfadnamenerweiterung) Keine Änderung der Positionsparameter ("$ @").
Für eine Lösung, die auf alle Shells portierbar ist (ja, alle POSIX-Versionen enthalten), ohne IFS zu ändern, oder set -f
verwenden Sie das (etwas komplexere) heredoc-Äquivalent:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_
echo "$second $fourth"
Verstehen Sie, dass diese Lösung (sowohl das Here-Doc als auch die Verwendung von <<<
werden alle nachgestellten Zeilenumbrüche entfernen.
Und dass dies auf einen " einzeiligen " variablen Inhalt ausgelegt ist.
Lösungen für Mehrzeilige sind möglich, erfordern jedoch komplexere Konstrukte.
Eine sehr einfache Lösung ist in der Bash-Version 4.4 möglich
readarray -d _ -t arr <<<"$string"
echo "array ${arr[1]} ${arr[3]}" # array numbers are zero based.
Es gibt keine Entsprechung für POSIX-Shells, da viele POSIX-Shells keine Arrays haben.
Für Shells mit Arrays gilt möglicherweise
Folgendes : (getestetes Arbeiten in attsh, lksh, mksh, ksh und bash)
set -f; IFS=_; arr=($string)
Aber mit einer Menge zusätzlicher Klempnerarbeiten zum Speichern und Zurücksetzen von Variablen und Optionen:
string='one_* *_three_four_five'
case $- in
*f*) noglobset=true; ;;
*) noglobset=false;;
esac
oldIFS="$IFS"
set -f; IFS=_; arr=($string)
if $noglobset; then set -f; else set +f; fi
echo "two=${arr[1]} four=${arr[3]}"
In zsh beginnen Arrays mit 1 und teilen die Zeichenfolge nicht standardmäßig.
Es müssen also einige Änderungen vorgenommen werden, damit dies in zsh funktioniert.
read
werden , sind einfach, solange OP nicht das 76. und 127. Element aus einer langen Zeichenfolge extrahieren möchte ...
readarray
könnte für diese Situation einfacher zu verwenden sein.
Mit zsh
könnten Sie den String (on _
) in ein Array aufteilen :
elements=(${(s:_:)string})
und dann auf jedes Element über den Array-Index zugreifen:
print -r ${elements[4]}
Beachten Sie, dass in zsh
(im Gegensatz zu ksh
/ bash
) Array-Indizes bei 1 beginnen .
set -f
, der ersten Lösung eine Warnung hinzuzufügen . ... *
vielleicht Sternchen ?
set -f
? Ich benutze read
/ nicht IFS
. Versuchen Sie meine Lösungen mit einer Zeichenfolge wie *_*_*
oder was auch immer ...
Ein anderes awk Beispiel; einfacher zu verstehen.
A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`
... and so on...
Kann auch mit Variablen verwendet werden.
Nehmen wir an:
this_str = "one_two_three_four_five"
Dann funktioniert folgendes:
A = `echo $ {this_str} | awk -F_ '{print $ 1}' `
B =` echo $ {this_str} | awk -F_ '{print $ 2}' `
C =` echo $ {this_str} | awk -F_ '{print $ 3}' `
... und so weiter ...