извлечь дату «2017-01-26» (в гггг-мм-дд) из файлов с именем «abcd.log.2017_01_26_23_30.0»

Если вам нужна оболочка с лучшей поддержкой ассоциативных массивов, попробуйте zsh.

В zsh (где ассоциативные массивы были добавлены в 1998 г. по сравнению с 1993 г. для ksh93 и 2009 г. для bash), $var или ${(v)var} расширяется до (непустых) значений хеша, ${(k)var} до (непустых) ключей (в том же порядке), и ${(kv)var} как для ключей, так и для значений.

Чтобы сохранить пустые значения, как и для массивов, вам нужно заключить в кавычки и использовать флаг @.

Таким образом, для вывода ключей и значений достаточно

printf '%s => %s\n' "${(@kv)var}"

Хотя для учета возможного пустого хеша вам следует сделать следующее:

(($#var)) &&  printf '%s => %s\n' "${(@kv)var}"

Также обратите внимание, что zsh использует гораздо более разумный и полезный синтаксис определения массива, чем ksh93's (скопировано bash):

typeset -A var
var=(k1 v1 k2 v2 '' empty '*' star)

Что значительно упрощает копирование или объединение ассоциативных массивов:

var2=("${(@kv)var1}")
var3+=("${(@kv)var2}")
var4=("${@kv)var4}" "${(@kv)var5}")

(вы не можете легко скопировать хэш без цикл с bash, и обратите внимание, что bash в настоящее время не поддерживает пустые ключи или ключи/значения с байтами NUL).

См. также zsh функции сжатия массива, которые обычно требуются для работы с ассоциативными массивами:

keys=($(<keys.txt)) values=($(<values.txt))
hash=(${keys:^values})
0
15.02.2017, 11:37
2 ответа

Использование групп захвата и $ BASH_REMATCH для извлечения битов строк:

for name in *.log.*; do
    if [[ "$name" =~ \.([0-9]{4})_([0-9]{2})_([0-9]{2}) ]]; then
        printf '%d-%d-%d from "%s"\n' \
            "${BASH_REMATCH[1]}" \
            "${BASH_REMATCH[2]}" \
            "${BASH_REMATCH[3]}" \
            "$name"
    fi
done

Вывод:

2017-01-26 from "abcd.log.2017_01_26_23_30.0"
2017-01-26 from "abcd.log.2017_01_26_23_35.0"
2017-02-20 from "abcd.log.2017_02_20_23_10.0"

Если вам нужна строка даты в переменной:

for name in *.log.*; do
    if [[ "$name" =~ \.([0-9]{4})_([0-9]{2})_([0-9]{2}) ]]; then
        datestring="$( printf '%d-%d-%d' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" )"
        printf '%s from "%s"\n' "$datestring" "$name"
    fi
done

В ksh93 замените BASH_REMATCH на .sh.match .

3
28.01.2020, 02:25

Я бы использовал perl и решайте это следующим образом:

#!/usr/bin/env perl
use strict;
use warnings;

while ( <> ) {
  my ( @date ) = m/(\d{4})\D(\d{2})\D(\d{2})/;
  my $date_str = join "-", @date;
  print $date_str,"\n";
}

Он сопоставляет «4 цифры», «2 цифры», «2 цифры» и переформатирует их, чтобы они были разделены - . Однако предполагается, что ваши номера расположены «правильно».

0
28.01.2020, 02:25

Теги

Похожие вопросы