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.