Bagaimana cara membagi nama file menjadi variabel?


11

Misalkan saya memiliki daftar file csv dengan format berikut:

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

The INT_V1_ & ASG_B1_V1_ adalah tetap, yang berarti semua file csv mulai dengan itu.
Bagaimana saya bisa membagi nama file menjadi variabel?
Misalnya, saya ingin menangkap Nama & menetapkannya ke variabel $Name.


Kenapa dengan tag "bash", jika Anda menggunakan ksh di AIX 7.1?
— Stéphane Chazelas

Saya ingin membuat skrip bash. Hanya saja saya ingin mencobanya terlebih dahulu di ksh, maaf telah menyebabkan Anda kesulitan.
— Juliet.Y

Jawaban:


7

Dengan 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

Dengan bashemulasi sh 4.3 atau lebih baru, ksh93t atau lebih baru atau zsh (meskipun dalam zsh, Anda lebih suka melakukan field=("${(@s:_:)field}")pemisahan daripada menggunakan operator split + glob non-sense sh) Anda dapat membagi string pada _karakter dan merujuknya dari akhir :

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

Atau (kurang lebih 3,2 atau lebih baru):

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

(yang mengasumsikan $fileberisi teks yang valid di lokal saat ini yang tidak dijamin untuk nama file kecuali jika Anda memperbaiki lokal ke C atau lokal lainnya dengan satu byte per karakter karakter).

Seperti zshdi *atas, .*itu serakah . Jadi yang pertama akan makan sebanyak *_mungkin, jadi sisanya .*hanya akan cocok dengan _string gratis.

Dengan ksh93, Anda bisa melakukannya

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

Dalam POSIX shskrip, Anda bisa menggunakan ${var#pattern}, ${var%pattern}operator ekspansi parameter standar:

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##*_}

Atau gunakan lagi operator split + glob:

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

Saya menggunakan bash di AIX7.1 & Saya sedang menguji di ksh. Entah bagaimana saya menemukan kesalahan yang menyatakan ksh: file: 0403-046 The specified subscript cannot be greater than 4095.untuk ${field[-1]}atau apa pun dalam formulir ${x[n]}.
— Juliet.Y

@ Juliet, ${field[-1]}adalah untuk bash-4.3+. Untuk ksh, gunakan salah satu dari solusi "POSIX". Dukungan untuk subskrip negatif tidak ditambahkan sebelum ksh93t (fitur yang berasal dari zsh).
— Stéphane Chazelas

Oke tercatat. Terima kasih banyak, skrip bekerja dengan baik.
— Juliet.Y

4

Anda bisa mengambil nilai bidang Anda <Name>dengan perintah ini:

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

(atau dengan awk):

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

Dan Anda dapat menempatkan mereka dalam variabel seperti ini:

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

atau

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

Tidak jelas dalam pertanyaan apakah Anda menginginkan variabel yang sama untuk semua nilai atau satu variabel tunggal untuk masing-masingnya.


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

Catatan yang _tidak spesial dan tidak perlu dikutip. Itu mengasumsikan nama file tidak mengandung karakter baris baru. Anda mungkin ingin menambahkan -d ''.
— Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.