2013-08-26 2 views
9

Я пытаюсь преобразовать HTML, содержащий таблицу в CSV-файл, используя сценарий bash.Использовать sed или awk для определения формата даты

До сих пор я acomplished следующие шаги:

  1. Преобразование в формат Unix (с dos2unix)
  2. Удалить все пробелы и табуляцию (с sed 's/[ \t]//g')
  3. Удалить все пустые строки (с sed ':a;N;$!ba;s/\n//g') (это необходимо, потому что в файле HTML есть пустая строка для каждой ячейки таблицы ... это не моя ошибка)
  4. Удалить ненужные <td> и <tr> теги (с sed 's/<t.>//g')
  5. Заменить </td> с '' (с sed 's/<\/td/,/g')
  6. Заменить </tr> с отслуживших линии (\n) символов (с sed 's/<\/tr/\n/g')

Конечно, я ставлю все это в трубопровод. Пока что он отлично работает. Есть один последний шаг, за которым я застрял: в таблице есть столбец с датами, который имеет формат dd/mm/yyyy, и я хотел бы преобразовать их в yyyy-mm-dd.

Есть ли (простой) способ сделать это (с sed или awk)?

образец данных (после всей sed трубы):

500,2,13/09/2007,30000.00,12,B-1 
501,2,15/09/2007,14000.00,8,B-2 

Ожидаемый результат:

500,2,2007-09-13,30000.00,12,B-1 
501,2,2007-09-15,14000.00,8,B-2 

Причина мне нужно сделать это, потому что мне нужно импортировать эти данные к MySQL. Я могу открыть файл в Excel и изменить формат вручную, но я бы хотел пропустить это.

ответ

7

Awk может сделать эту задачу довольно легко:

awk ' 
    BEGIN { FS = OFS = "," } 
    { split($3, date, /\//) 
     $3 = date[3] "-" date[2] "-" date[1] 
     print $0 
    } 
' infile 

Это дает:

500,2,2007-09-13,30000.00,12,B-1 
501,2,2007-09-15,14000.00,8,B-2 
4

awk будет работать следующим образом:

echo 08/26/2013 | awk -F/ '{printf "%s-%s-%s\n",$3,$2,$1}' 

, как бы один из них bash варианты: использующих только

IFS=/ read m d y < <(echo 08/26/2013); echo "${y}-${m}-${d}" 
IFS=/ read m d y <<< "08/26/2013"; echo "${y}-${m}-${d}" 

Если вы решили использовать ksh, где подоболочка не используется для последнего компонента трубопровода, это должно работать, а также:

echo 08/26/2013 | IFS=/ read m d y; echo "${y}-${m}-${d}" 

В последнее время bash, вы также можете использовать shopt -s lastpipe в скрипте, чтобы позволить вышеупомянутому вызову работать, но он не будет работать в командной строке (спасибо @ mklement0 в комментариях ниже).

Я оставлю это до вас, чтобы выяснить, как интегрировать его с остальными ...

+0

Приятная работа, но команда 'read' не будет работать, потому что' read' работает в _subshell_ в этом случае; используйте 'echo '08/26/2013 '| {IFS =/read m d y; echo "$ {y} - $ {m} - $ {d}"; } 'или ' IFS =/read m d y <<< '08/26/2013'; echo "$ {y} - $ {m} - $ {d}" ' – mklement0

+1

@ mklement0 Ах, да ... забыл про эту мелочь. Однако он работал бы в 'ksh'. Другой альтернативой будет 'IFS =/read m d y <<(echo 08/26/2013)', чтобы избежать подоболочки (хотя 'echo' будет находиться в подоболочке). – twalberg

+0

Хорошие моменты, хотя '<<<', вероятно, наиболее эффективен здесь. В Bash v4.2 + вы также можете использовать 'shopt -s lastpipe' (но только в скриптах). Могу ли я предложить вам обновить свой ответ одним из рабочих решений? – mklement0

7
sed -E 's,([0-9]{2})/([0-9]{2})/([0-9]{4}),\3-\2-\1,g' 
+0

Вставил это как пример первого прохода, чтобы все было в порядке, и оно работало дословно! Спасибо @ash! – Matthew

1

поправка к AWK Предположим, вы ищете гггг-мм-дд (не гггг дд-мм)

echo 26.08.2013 | awk -F/'{printf "% s-% s-% s \ n", $ 3, $ 1, $ 2}'

2

До сих пор все ответы очень специфичны для вопроса OP. Вот более общий подход, бег (GNU, для -d опции) date через awk:

awk 'BEGIN{FS=","} 
    { 
     "date -d\"" $3 "\" +%Y-%m-%d" | getline mydate; 
     print $1 "," $2 "," mydate "," $4 "," $5 "," $6 
    }' 

Конечно, этот подход будет работать только если формат даты ввода обрабатывается date. AFAICS это не относится к dd/mm/yyyy, к сожалению. Можно попробовать other commands, чем date (не проверено).

Редактировать: Реализован комментарий mklement0.

Редактировать 2: На самом деле это не работает с mawk, что по умолчанию является Debian awk. Очевидным решением является установка gawk, когда это возможно.

+1

++, но вы должны упомянуть, что _GNU_ 'date' требуется из-за' -d'; аналогично, '| &' является расширением GNU Awk, но на самом деле не требуется здесь: '|' будет делать, что заставляет его работать со всеми Awks. Наконец, я предлагаю вам использовать пробелы между конкатенированными строками, как для визуальной ясности, так и для того, чтобы показать, что конкатенация строк в Awk работает по-разному , чем в оболочке; например, '' date -d '"$ 3"' +% Y-% m-% d "' (Я также добавил одинарные кавычки для защиты от поля, имеющего встроенные пространства). – mklement0

+1

@ mklement0: Спасибо за ваши предложения, я отредактировал ответ. Одиночные кавычки не будут делать, я заменил их двойными кавычками. –

+1

Благодарим за обновление ответа и благодарность за то, что он поймал мою ошибку с одной кавычкой (просто указать ее явно: одинарные кавычки не могут использоваться внутри скрипта Awk, потому что сценарий в целом одинарный). – mklement0

Смежные вопросы