Antworten:
Verwenden Sie cutmit _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 echoanstelle 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 IFSdas 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 readeingebauten.
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
unset IFSkehrt nicht IFSzum 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 IFSwird nicht IFSauf 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 readaufgrund 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 awkAntwort 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, $aanstatt 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 -fverwenden 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 ...
readarraykönnte für diese Situation einfacher zu verwenden sein.
Mit zshkö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 ...