Làm cách nào để chia tệp theo một cột (bao gồm tiêu đề) và đổi tên các tệp được tạo?


7

Tôi có một .txtví dụ có thể được minh họa như thế này:

NAME | CODE
name1 | 001
name2 | 001
name3 | 002
name4 | 003
name5 | 003
name6 | 003

Tôi cần phải viết một tập lệnh để phân chia tập tin này theo CODEcột, vì vậy trong trường hợp này tôi sẽ nhận được điều này:

file 1:
NAME | CODE
name1 | 001
name2 | 001

file 2:
NAME | CODE
name3 | 002

file 3:
NAME | CODE
name4 | 003
name5 | 003
name6 | 003

Theo một số nghiên cứu, sử dụng awk sẽ hoạt động:

$ awk -F, '{print > $2".txt"}' inputfile

Vấn đề là, tôi cũng cần bao gồm tiêu đề cho dòng đầu tiên và tôi cần tên tệp phải khác nhau. Thay vì 001.txt, ví dụ, tôi cần tên tệp giống như thế FILE_$FILENAME_IDK.txt.

Câu trả lời:


8

Bạn có thể thử như thế này:

awk 'NR==1{h=$0; next}
!seen[$3]++{f="FILE_"FILENAME"_"$3".txt";print h > f} 
{print >> f}' infile

Ở trên lưu tiêu đề trong một biến h( NR==1{h=$0; next}), nếu $3không nhìn thấy ( !seen[$3]++nghĩa là nếu đó là lần đầu tiên nó gặp giá trị hiện tại $3), nó đặt tên tệp ( f=...)và ghi tiêu đề thành tên tệp ( print h > f). Sau đó, nó nối thêm toàn bộ dòng vào tên tệp ( print >> f). Nó sử dụng mặc định FS(dấu tách trường): để trống . Nếu bạn muốn sử dụng |dưới dạng FS(hoặc thậm chí là biểu thức chính quy gnu awk), hãy xem bình luận của cas 'bên dưới.


Tập lệnh này cũng tạo ra một tệp có tên CODE.txt. Ngoài ra, nội dung tệp FILE_inputfile_003.txt không hoàn toàn đúng: NAME | Tên mã 4 | 003 tên5 | 003 TÊN | Tên mã6 | 003 Sẽ thật tuyệt nếu bạn giải thích một chút về kịch bản của mình =)
Kira

1
hoặc, nếu bạn muốn sử dụng |làm dấu tách trường : awk -F'|' 'NR==1{h=$0; next} !seen[$2]++{f="FILE_"FILENAME"_"$2".txt";gsub(/ /,"",f);print h > f} {print >> f}'. đó gsub()là tước khoảng trắng ở đầu trường 2, ví dụ `001` ->001
cas

2
hiểu rồi. awk -F' \\| ' 'NR==1{h=$0; next} !seen[$2]++{f="FILE_"FILENAME"_"$2".txt";print h > f} {print >> f}' cảm ơn stackoverflow.com/questions/25867060/ Lời
cas

1
@cas FS là một regex ăn \ , bạn cần thoát \ đầu tiên và sau đó sử dụng thoát \ để thoát |. Không trực quan lắm, được cấp.
terdon

1
@terdon - đúng, nó được gọi là regex động
don_crissti

1

Tôi cá là ai đó sẽ nghĩ ra một cái lót, nhưng tôi phải tạo một kịch bản:

in='inputfile'
header=$(head -n1 "$in")
codes=($(sed -n 's/.*| \([0-9]\+\)/\1/p' "$in" | uniq ))
for line in "${codes[@]}"; do
    out="file_$i.txt"
    echo "$header" > "$out"
    grep "|.* $line$" "$in" >> "$out"
done

Khi tôi thực thi tập lệnh, tôi nhận được lỗi sau: script.sh: 8: script.sh: i ++: không tìm thấy.
Glem

Bạn đang sử dụng bash? Kiểm tra cập nhật câu trả lời.
Kira

Có, #! / Bin / bash
Glem

Bây giờ với i=$((i+1))nó là hoạt động đúng?
Kira

1
Vâng, cái đó đã trở lại và cắn tôi! Bạn hoàn toàn đúng, lời xin lỗi của tôi. Các dòng mới đang làm cho nó hoạt động mặc dù nó là một chuỗi. Tôi đã thực hiện một vài cải tiến để chuộc lại lỗi lầm của mình và để tôi lấy lại downvote.
terdon
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.