Wie teile ich den Dateinamen in eine Variable auf?


10

Angenommen, ich habe eine Liste von CSV-Dateien mit dem folgenden Format:

INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv
ASG_B1_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv

Die INT_V1_ & ASG_B1_V1_ ist festgelegt, was bedeutet , alle CSV - Dateien mit ihm beginnen.
Wie kann ich die Dateinamen in Variablen aufteilen?
Zum Beispiel wollte ich den Namen erfassen und einer Variablen zuweisen $Name.


Warum das "bash" -Tag, wenn Sie ksh unter AIX 7.1 verwenden?
— Stéphane Chazelas

Ich möchte ein Bash-Skript erstellen. Nur, dass ich es zuerst auf ksh versuchen wollte, tut mir leid, dass ich dir Ärger gemacht habe.
— Julia.Y

Antworten:


7

Mit zsh:

file='INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv'

setopt extendedglob
if [[ $file = (#b)*_(*)_(*)_(*)_(*).csv ]]; then
  product=$match[1] id=$match[2] name=$match[3] date=$match[4]
fi

Mit bash4.3 oder neuer, ksh93t oder neuer oder zsh in der Sh-Emulation (obwohl zshSie dies eher field=("${(@s:_:)field}")zum Teilen tun als mit dem unsinnigen Operator split + glob von sh) können Sie die Zeichenfolge auf _Zeichen aufteilen und sie vom Ende aus referenzieren ::

IFS=_
set -o noglob
field=($file) # split+glob  operator
date=${field[-1]%.*}
name=${field[-2]}
id=${field[-3]}
product=${field[-4]}

Oder (Bash 3.2 oder neuer):

if [[ $file =~ .*_(.*)_(.*)_(.*)_(.*)\.csv$ ]]; then
  product=${BASH_REMATCH[1]}
  id=${BASH_REMATCH[2]}
  name=${BASH_REMATCH[3]}
  date=${BASH_REMATCH[4]}
fi

(Dies setzt voraus, dass $filedas aktuelle Gebietsschema gültigen Text enthält, der für Dateinamen nur dann garantiert wird, wenn Sie das Gebietsschema auf C oder ein anderes Gebietsschema mit einem Einzelbyte-Zeichensatz pro Zeichen festlegen.)

Wie zsh‚s *oben, das .*ist gierig . Der erste frisst also so viele *_wie möglich, der Rest .*passt nur zu _freien Saiten.

Mit ksh93könnte man machen

pattern='*_(*)_(*)_(*)_(*).csv'
product=${file//$pattern/\1}
id=${file//$pattern/\2}
name=${file//$pattern/\3}
date=${file//$pattern/\4}

In einem POSIX - shSkript, können Sie die verwenden ${var#pattern}, ${var%pattern}Standardparameter Expansion Operatoren:

rest=${file%.*} # remove .csv suffix
date=${rest##*_} # remove everything on the left up to the rightmost _
rest=${rest%_*} # remove one _* from the right
name=${rest##*_}
rest=${rest%_*}
id=${rest##*_}
rest=${rest%_*}
product=${rest##*_}

Oder verwenden Sie den Operator split + glob erneut:

IFS=_
set -o noglob
set -- $file
shift "$(($# - 4))"
product=$1 id=$2 name=$3 date=${4%.*}

Ich verwende Bash unter AIX7.1 und teste derzeit in ksh. Irgendwie stoße ich auf einen Fehler, der ksh: file: 0403-046 The specified subscript cannot be greater than 4095.für ${field[-1]}oder irgendetwas in der Form angibt ${x[n]}.
— Julia.Y

@ Julia, ${field[-1]}war für bash-4.3+. Für kshverwenden, eine der „POSIX“ Lösungen. Die Unterstützung für negative Indizes wurde vor ksh93t (eine Funktion mit Ursprung in zsh) nicht hinzugefügt.
— Stéphane Chazelas

OK notiert. Vielen Dank, die Skripte funktionieren gut.
— Julia.Y

4

<Name>Mit diesem Befehl können Sie die Werte Ihres Feldes übernehmen :

cut -d'<' -f4 < csvlist | sed -e 's/>_//g'

(oder mit awk):

awk -F'<' '{print $4}' < csvlist | sed -e 's/>_//g'

Und Sie können sie in eine Variable wie diese einfügen:

variable_name=$(cut -d'<' -f4 < csvlist | sed -e 's/>_//g')

oder

awk -F'<' '{print $4}' < csvlist | sed -e 's/>_//g'

In der Frage ist nicht klar, ob Sie für alle Werte dieselbe Variable oder für jeden eine einzelne Variable wünschen.


1
file='INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv'
IFS=\_ read -r x x product id name date x <<< "$file"
date=${date%.*}

Beachten Sie, dass dies _nichts Besonderes ist und nicht zitiert werden muss. Dies setzt voraus, dass der Dateiname keine Zeilenumbrüche enthält. Möglicherweise möchten Sie eine hinzufügen -d ''.
— Stéphane Chazelas
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.