Как я могу работать \1 в sed (или $1 в awk)?

Попробуйте перенастроить запущенные локали

sudo dpkg-reconfigure locales

Экспорт LANG в .bashrc повлияет только на приложения, запущенные из терминала.

В качестве альтернативы вы можете редактировать от имени root файл /etc/default/locale, но убедитесь, что в нем присутствуют нужные вам локали, выполнив locale -a.

2
22.08.2018, 02:54
6 ответов

В awk вы можете использовать

awk '{ cmd = "date -d@" $1; cmd | getline date; close (cmd); $1 = date; print $0; }'

Чтобы ограничиться числовыми значениями, проверьте шаблон, состоящий только из цифр:

awk '$1 ~ /^[0-9]*$/ { cmd = "date -d@" $1; cmd | getline $1; close (cmd); print $0; }'
0
27.01.2020, 21:55

Использование Awk:

{
  "date -d @" $1 | getline $1
}
1

Результат:

Tue, Aug 21, 2018  4:47:30 PM some text
Tue, Aug 21, 2018  4:47:31 PM some more text
Tue, Aug 21, 2018  4:47:32 PM text
0
27.01.2020, 21:55

Если у вас есть GNU awk (, также известный как gawk), вы можете использовать его встроенную функцию -в strftimeдля преобразования времени эпохи в формат по вашему выбору:

$ TZ=UTC gawk '{$1 = strftime("%a %b %d %H:%M:%S %Z %Y", $1)} 1' file
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text

Вы также можете использовать perl с модулем POSIX:

$ TZ=UTC perl -MPOSIX -alne '
    print join " ", strftime("%a %b %d %H:%M:%S %Z %Y", localtime shift @F), @F
  ' file
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text

Хотя реализация GNU sedимеет модификатор e, позволяющий выполнять внешние команды, он работает со всем пространством шаблонов -, что делает его довольно громоздким для использования на практике.

2
27.01.2020, 21:55

Пакет dateutils отлично подходит для таких вещей,особенно инструмент dconv. (При установке в системах Ubuntu команда доступна как dateutils.dconv.)

Вот иллюстрация:

$ cat testfile.txt 
1534888050 some text
1534888051 some more text
1534888052 text
$ dateutils.dconv -i '%s' -f '%a %b %d %T %Y' -S <testfile.txt 
Tue Aug 21 21:47:30 2018 some text
Tue Aug 21 21:47:31 2018 some more text
Tue Aug 21 21:47:32 2018 text
$ dateutils.dconv -i '%s' -f '%F %T' -S <testfile.txt 
2018-08-21 21:47:30 some text
2018-08-21 21:47:31 some more text
2018-08-21 21:47:32 text
$ 

Флаг -Sявляется ключевым; он указывает инструменту работать в «режиме sed» и включать в вывод текст даты, отличный от -.

Флаг -iуказывает формат входной даты, а флаг -fуказывает формат выходной даты.

3
27.01.2020, 21:55

Если sed обязателен, используйте GNU sed с:

$ sed -e 'h;s/^\([^ ]*\) \(.*\)/date -ud @\1/;e' -e 'x;s//\2/;x;G;s/\n/ /' infile.txt
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text

В противном случае снаряд мог сделать:

$ TZ=UTC0 bash -c 'while read a b; do printf '\''%(%c)T %s\n'\'' "$a" "$b"; done <infile'
Tue 21 Aug 2018 09:47:30 PM UTC some text
Tue 21 Aug 2018 09:47:31 PM UTC some more text
Tue 21 Aug 2018 09:47:32 PM UTC text

Или, что еще лучше, используйте awk:

$ awk '{c="date -ud @" $1;c|getline $1;close(c)}1' infile.txt
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text
0
27.01.2020, 21:55

Что вам нужно понять, так это то, что GNU sedзаменяет все пространство шаблонов результатом вычисления команды в RHS s///e. Поэтому, чтобы приспособиться к такому поведению, мы используем комбинацию команд echo + date, как показано:

 sed -e  's/^\([1-9][0-9]*\)\(.*\)/echo "`date -d@\"\1\"`\2"/e'  input-file.txt

А с Perlвсе просто в том, что то, что сопоставляется в левой части, заменяется только в правой части, как можно было бы интуитивно ожидать также:

  perl -pe 's/(\d+)/qx(date -d@"$1") =~ s|\n||r/e'  input-file.txt 
0
27.01.2020, 21:55

Теги

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