Extrai a última linha da string multilinha

3

A saída de exif é assim:

ExifMnoteCanon: Loading entry 0xcf27 ('(null)')...
ExifMnoteCanon: Loading entry 0x3ca8 ('(null)')...
ExifMnoteCanon: Loading entry 0xf88a ('(null)')...
2013:08:22 18:01:16

No meu script bash, eu armazeno isso em uma variável:

datetime="$(exif --debug --machine-readable --tag=DateTimeOriginal "$file" 2>&1)"

Eu quero extrair a última linha deste usando a substituição de parâmetro bash. Eu pensei que isso funcionaria:

datetime="${datetime##*\n}"

Mas a saída é então:

ull)')...
2013:08:22 18:01:16

Por que isso não funciona e como posso corrigi-lo?

    
por David Kennedy 25.12.2015 / 21:34

3 respostas

3

Use a sequência de escape do estilo ANSI C, $'\n' para indicar nova linha:

% echo "$datetime"       
ExifMnoteCanon: Loading entry 0xcf27 ('(null)')...
ExifMnoteCanon: Loading entry 0x3ca8 ('(null)')...
ExifMnoteCanon: Loading entry 0xf88a ('(null)')...
2013:08:22 18:01:16

% echo "${datetime##*\n}"
ull)')...
2013:08:22 18:01:16

% echo "${datetime##*$'\n'}"
2013:08:22 18:01:16

Como você pode ver, o \n está sendo tratado como literal n .

    
por 25.12.2015 / 21:39
2

Embora o $'' seja bastante portátil nos dias de hoje (o BSD sh suporta, por exemplo, apesar de seu fork downstreamdash não) , POSIXLY:

eval 'printf "%s\n" "${datetime##*"'"$(printf '\n"')}\""

... funcionará, mesmo que seja irritante. Eu normalmente mantenho uma nova linha em uma variável $nl , e assim:

printf "%s\n" "${datetime##*$nl}"

... é muito mais gerenciável. E é claro que você pode apenas fazer:

printf "%s\n" "${datetime##*"
"}"

... mas é um pouco engraçado, talvez.

    
por 25.12.2015 / 23:54
2

Como alternativa, com uma versão recente de bash , você poderia usar mapfile e processar substituição para armazenar exif output em uma matriz e acessar o último elemento

mapfile -t arr < <(
         exif --debug --machine-readable --tag=DateTimeOriginal "$file" 2>&1)
printf '%s\n' "${arr[@]:(-1)}"
2013:08:22 18:01:16
    
por 26.12.2015 / 05:01

Tags