Làm cách nào tôi có thể chuyển đổi dữ liệu được phân tách bằng tab thành dữ liệu được phân cách bằng dấu phẩy?


8

Tôi đang yêu cầu một danh sách các ảnh chụp nhanh ec2 thông qua công cụ dòng lệnh ec2 của amazon:

ec2-describe-snapshots -H --hide-tags > snapshots.csv

Dữ liệu trông giống như thế này:

SnapshotId      VolumeId        StartTime   OwnerId         VolumeSize  Description
snap-00b66464   vol-b99a38d0    2012-01-05  5098939         160         my backup

Làm cách nào tôi có thể chặn dữ liệu trước khi chuyển hướng đến snapshots.csvvà thực hiện các việc sau:

  • thay thế "tab" bằng dấu phẩy
  • đóng gói các giá trị với trích dẫn
  • nếu một giá trị là tất cả các số, tiền tố nó với một =để excel sẽ đối xử với nó dưới dạng văn bản - ví dụ OwnerIdnên "=5098939"(cái này là không cần thiết nếu nó không thể được thực hiện inline và thay vào đó sẽ đòi hỏi một tập tin script hoặc chức năng)

sản phẩm chất lượng:

"SnapshotId","VolumeId","StartTime","OwnerId","VolumeSize","Description"
"snap-00b66464","vol-b99a38d0","2012-01-05","=5098939","=160","my backup"

Đây là nơi ai đó bảo bạn nhập bằng các tab. Hoặc họ sẽ, nếu Excel không bị crack.
Ignacio Vazquez-Abrams

Vâng, tôi đang cố gắng để giúp xuất sắc hơn một chút vì nó dường như không làm nó quá nóng. Ngoài ra có một tệp CSV chỉ có thể được mở thay vì phải sử dụng lệnh menu nhập luôn luôn tốt. Tôi đã thử thay đổi tiện ích mở rộng thành ".tsv" nhưng không có may mắn.
cwd

Tôi nghĩ rằng đầu ra mong muốn của bạn là một chút tắt. Bạn có rất nhiều trường trống trong đó (dấu ngoặc kép trống).
Patrick

Câu trả lời:


10
#!/usr/bin/awk -f

BEGIN { FS = "\t"; OFS = "," }
{
    for(i = 1; i <= NF; i++) {
        if ($i + 0 == $i) { $i = "=" $i }
        else gsub(/"/, "\"\"", $i);
        $i = "\"" $i "\""
    }
    print
}

Giả sử bạn đặt tên này convert.awk, bạn có thể gọi bằng một trong hai

ec2-describe-snapshots -H --hide-tags | awk -f convert.awk > snapshots.csv

hoặc (sau khi thêm quyền thực thi, chmod a+x convert.awk)

ec2-describe-snapshots -H --hide-tags | ./convert.awk > snapshots.csv

Điều này sẽ tạo một cột mới cho mỗi tab, nó sẽ giữ cột bình luận cùng nhau (trừ khi nó chứa các tab), nhưng thêm các cột trống (mặc dù đó là cách đầu ra mẫu của bạn trông, vì vậy có thể bạn thực sự muốn điều đó). Nếu bạn muốn phân tách trên tất cả các khoảng trắng (điều này sẽ thu gọn các tab bổ sung trong bảng nhưng đặt từng từ trong mô tả dưới dạng một cột mới), hãy đưa ra FS="\t";tuyên bố.

Đối với thế hệ tương lai, nếu bạn không cần "s hoặc =s hoặc khoảng trắng nhúng, bạn có thể làm cho nó một lớp lót:

awk -v OFS=, '{$1=$1;print}'

Giải pháp sạch đẹp. Tưởng rằng nó sẽ kết thúc xấu hơn thế nhiều, nhưng sau đó tôi không phải là người ngu ngốc :-)
Patrick

Vì vậy, tôi có lưu nó vào một tập tin như ./convert.sh, chmod + x, và sau đó dẫn đầu vào vào nó để nó sẽ in đầu ra không? Tôi đang gặp lỗi : /usr/bin/awk: syntax error at source line 1 context is >>> . <<< /convert.sh.
cwd

@cwd Bạn có thể lưu nó trong một tệp, tôi đề nghị convert.awkchỉ ra đó là awktập lệnh chứ không phải tập lệnh bash. Tôi đã cập nhật bài đăng với dòng lệnh đầy đủ và lưu ý rằng tôi đã thêm một -flá cờ mà tôi đã quên vào dòng đầu tiên (điều đó nói với nó để diễn giải tệp dưới dạng các lệnh).
Kevin

Phiên bản một lớp xử lý bất kỳ khoảng trắng nào như một dấu tách trường, không chỉ các tab. Cần một -F '\ t' trước -V.
Paul_Pedant

4

Đây là một giải pháp perl. Điều này có thể khả thi với sed / awk, nhưng việc kiểm tra phần số có thể sẽ khiến nó trở nên khá xấu xí.

ec2-describe-snapshots -H --hide-tags | \
perl -e 'use Scalar::Util qw(looks_like_number);
         while (chomp($line = <STDIN>)) {
             print(join(",", map { "\"" . (looks_like_number($_) ? "=$_" :
                                           do {s/"/""/g; $_}) . "\"" }
             split(/\t/, $line)) . "\n");
         }' \
> snapshots.csv

3

Nếu bạn chỉ lười biếng như tôi và muốn làm tất cả trên một dòng lệnh mà không viết kịch bản, thì đây là cách tôi sẽ làm.

ec2-describe-snapshots -H --hide-tags | sed -e 's/^I/","/g' | sed -e 's/^/"/' | sed -e 's/$/"/'> snapshots.csv

Việc ^Inày được thực hiện bằng cách nhấn ctrl+ v i.

Đầu tiên sedhoán đổi tất cả tabscho ",". Cái thứ hai sedchèn a "ở đầu mỗi dòng và chiếc sed cuối cùng chèn một đóng "ở cuối mỗi dòng.


Làm thế nào bạn có được ctrl + vi để hiển thị như vậy?
Burhan Khalid

@burhan Cú pháp là <kbd>text</kbd>.
jw013

3
Hoặc trong một dòng: sed -e 's/^I/","/g' -e 's/.*/"&"/'hoặc thậm chí ngắn hơn sed -e 's/^I/","/g;s/.*/"&"/'.
Arcege

3

Một giải pháp khác của Perl:

#!/usr/bin/perl -wln
use strict;

my($n,$s);chomp();
for $s ( split(/\t/,$_) )
{
    $s = '='.$s if ($s =~ /^\d+$/);
    $n.= '"'.$s.'",';
}
$n =~ s/(.*),/$1/;print $n;

gọi với ec2-describe-snapshots -H --hide-tags | /var/tmp/script.pl > output.txt


Scalar :: Util không phải là một mô-đun bên ngoài, nó đi kèm với perl tiêu chuẩn.
Patrick

Thật. Xin lỗi vì từ ngữ kém ý kiến ​​của tôi. Cảm ơn bạn đã sửa chữa.
Jim

1

sed là tiện ích linux hữu ích nhất mà tôi từng gặp.

sed 's/\t/","/g' TabSeparatedValues.txt > CommaSeparatedValues.csv
sed -i 's/.*/"&"/' CommaSeparatedValues.csv

Lệnh đầu tiên thay thế tất cả các tab trong mỗi dòng bằng dấu phẩy và dấu ngoặc kép. Lệnh thứ hai chèn dấu ngoặc kép ở đầu và cuối của mỗi dòng, sao cho mỗi giá trị sẽ được bao quanh trong dấu ngoặc kép, cho phép dấu phẩy là một phần của giá trị.


0

Điều này có thể làm việc cho bạn:

sed 's/\t\+/,/g;s/^\|$/"/g;s/,/"&"/g;s/"\([0-9]\+\)"/"=\1"/g' file
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.