2013-08-26 40 views
9

Tôi đang cố chuyển đổi HTML chứa bảng thành tệp .csv bằng cách sử dụng tập lệnh bash.Sử dụng sed hoặc awk để sửa định dạng ngày

Cho đến nay tôi đã acomplished các bước sau:

  1. Chuyển đổi sang định dạng Unix (với dos2unix)
  2. Hủy bỏ tất cả không gian và các tab (với sed 's/[ \t]//g')
  3. Hủy bỏ tất cả các dòng trống (với sed ':a;N;$!ba;s/\n//g') (điều này là cần thiết, vì tệp HTML có một dòng trống cho mỗi ô của bảng ... đó không phải là lỗi của tôi)
  4. Xóa các bộ sưu tập không cần thiết <td><tr> (với))
  5. Thay </td> với '' (với sed 's/<\/td/,/g')
  6. Thay </tr> với (\n) ký tự end-of-line (với sed 's/<\/tr/\n/g')

Tất nhiên, tôi đặt tất cả điều này trong một đường ống. Cho đến nay, nó hoạt động rất tốt. Có một bước cuối cùng tôi bị mắc kẹt: Bảng có một cột có ngày, có định dạng dd/mm/yyyy và tôi muốn chuyển đổi chúng thành yyyy-mm-dd.

Có cách nào (đơn giản) để làm điều đó (với sed hoặc awk)?

mẫu dữ liệu (sau khi toàn bộ sed ống):

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

Dự kiến ​​kết quả:

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

Lý do tôi cần phải làm điều này là bởi vì tôi cần phải nhập dữ liệu này sang MySQL. Tôi có thể mở tập tin trong Excel và thay đổi định dạng bằng tay, nhưng tôi muốn bỏ qua nó.

Trả lời

7

Awk có thể làm nhiệm vụ này khá dễ dàng:

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

Nó mang lại:

500,2,2007-09-13,30000.00,12,B-1 
501,2,2007-09-15,14000.00,8,B-2 
4
sed "s:,\([0-9]\+\)/\([0-9]\+\)/\([0-9]\+\),:,\3-\2-\1,:" 
4

awk sẽ làm việc cho điều này:

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

như sẽ là một trong những bash tùy chọn -only:

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}" 

Nếu bạn tình cờ sử dụng ksh, nơi một subshell không được sử dụng cho các thành phần cuối cùng của một đường ống, điều này sẽ làm việc cũng như:

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

Trong gần đây bash, bạn cũng có thể sử dụng shopt -s lastpipe trong tập lệnh để cho phép lời gọi ở trên hoạt động tốt, nhưng nó sẽ không hoạt động trên dòng lệnh (nhờ @ mklement0 trong các nhận xét bên dưới).

Tôi sẽ để nó tùy thuộc vào bạn để tìm ra cách để tích hợp nó với phần còn lại ...

+0

Tốt, nhưng lệnh 'đọc' dựa trên sẽ không hoạt động, vì' đọc' chạy trong _subshell_ trong trường hợp này; sử dụng 'echo '08/26/2013' | {IFS =/đọc m d y; echo "$ {y} - $ {m} - $ {d}"; } 'hoặc ' IFS =/đọc m d y <<< '26/08/2013'; echo "$ {y} - $ {m} - $ {d}" ' – mklement0

+1

@ mklement0 Ah, vâng .... quên mất chi tiết nhỏ đó. Nó sẽ hoạt động trong 'ksh'. Một phương án khác sẽ là 'IFS =/read m d y <<(echo 08/26/2013)' để tránh subshell (mặc dù 'echo' sẽ nằm trong một subshell). – twalberg

+0

Điểm tốt, mặc dù '<<<' có lẽ là hiệu quả nhất ở đây. Trong Bash v4.2 + bạn cũng có thể sử dụng 'shopt -s lastpipe' (nhưng chỉ trong các script). Tôi có thể đề nghị bạn cập nhật câu trả lời của mình bằng một trong các giải pháp làm việc không? – mklement0

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

Dán nội dung này vào làm ví dụ đầu tiên để làm mọi việc và nó hoạt động đúng nguyên văn! Cảm ơn @ash! – Matthew

1

chỉnh để awk giả sử bạn tìm kiếm yyyy-mm-dd (không yyyy-dd-mm)

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

2

Cho đến nay mọi câu trả lời đều rất cụ thể đối với vấn đề của OP. Đây là một cách tiếp cận tổng quát hơn, chạy (GNU, cho -d tùy chọn) date qua awk:

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

Tất nhiên phương pháp này sẽ làm việc như là chỉ khi định dạng ngày đầu vào được xử lý bởi date. AFAICS đây không phải là trường hợp cho dd/mm/yyyy, thật không may. Người ta có thể thử other commands hơn date (không được kiểm tra).

Chỉnh sửa: Đã thực hiện nhận xét của mklement0.

Chỉnh sửa2: Thực ra điều này không hoạt động với mawk, là cài đặt mặc định awk của Debian. Giải pháp rõ ràng là cài đặt gawk khi có thể.

+1

++, nhưng bạn nên đề cập rằng _GNU_ 'ngày' là bắt buộc do' -d'; tương tự, '| &' là một phần mở rộng GNU Awk, nhưng không thực sự cần thiết ở đây: '|' sẽ làm, mà làm cho nó làm việc với tất cả Awks. Cuối cùng, tôi đề nghị bạn sử dụng khoảng trống giữa các chuỗi được ghép nối, cả cho hình ảnh rõ ràng và để hiển thị chuỗi nối trong Awk hoạt động khác nhau so với trong vỏ; ví dụ: '" date -d '"$ 3"' +% Y-% m-% d "' (Tôi cũng đã thêm dấu nháy đơn để bảo vệ khỏi trường có khoảng trắng được nhúng). – mklement0

+1

@ mklement0: Cảm ơn các đề xuất của bạn, tôi đã chỉnh sửa câu trả lời. Dấu nháy đơn sẽ không thực hiện, tôi đã thay thế chúng bằng dấu nháy kép thoát. –

+1

Cảm ơn bạn đã cập nhật câu trả lời và cảm ơn vì đã gặp lỗi đơn trích dẫn của tôi (chỉ cần nêu rõ ràng: các dấu nháy đơn không thể được sử dụng bên trong tập lệnh Awk, vì toàn bộ tập lệnh được trích dẫn một lần). – mklement0

Các vấn đề liên quan