Como dividir o nome do arquivo na variável?

6

Suponha que eu tenha uma lista de arquivos csv com o seguinte formato:

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

O INT_V1 _ & ASG_B1_V1 _ é corrigido, o que significa que todos os arquivos csv começam com ele.
Como posso dividir os nomes dos arquivos em variável?
Por exemplo, eu queria capturar o Nome & atribua-o a uma variável $Name .

    
por Juliet.Y 07.03.2017 / 10:44

3 respostas

6

com 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

Com bash 4.3 ou mais recente, ksh93t ou mais recente ou em emsh sh (embora em zsh , você preferiria simplesmente fazer field=("${(@s:_:)field}") para dividir do que usando o operador não-sentido split + glob de sh ) você pode dividir a string em _ caracteres e referenciá-los no final:

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

Ou (bash 3.2 ou mais recente):

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

(que assume $file contém texto válido no código do idioma atual que não é garantido para nomes de arquivos, a menos que você corrija o código de idioma para C ou outro código de idioma com um único byte por caractere charset).

Como zsh ' * acima, o .* é ganancioso . Assim, o primeiro vai comer o máximo de *_ possível, então o .* restante corresponderá apenas a _ -free strings.

Com ksh93 , você poderia fazer

pattern='*_(*)_(*)_(*)_(*).csv'
product=${file//$pattern/}
id=${file//$pattern/}
name=${file//$pattern/}
date=${file//$pattern/}

Em um script POSIX sh , você pode usar os operadores de expansão de parâmetro ${var#pattern} , ${var%pattern} :

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

Ou use o operador split + glob novamente:

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

Você pode pegar os valores do seu campo <Name> com este comando:

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

(ou com awk ):

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

E você pode colocá-los em uma variável como esta:

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

ou

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

Não está claro na pergunta se você deseja a mesma variável para todos os valores ou uma única variável para cada um deles.

    
por 07.03.2017 / 10:54
1
file='INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv'
IFS=\_ read -r x x product id name date x <<< "$file"
date=${date%.*}
    
por 07.03.2017 / 13:50

Tags