Câu trả lời:
Đối với cut(1)
trang người đàn ông:
Sử dụng một và chỉ một trong số -b, -c hoặc -f. Mỗi DANH SÁCH được tạo thành từ một phạm vi hoặc nhiều phạm vi được phân tách bằng dấu phẩy. Đầu vào được chọn được viết theo cùng thứ tự được đọc và được viết chính xác một lần.
Nó đạt đến trường 1 trước, do đó được in, tiếp theo là trường 2.
Sử dụng awk
thay thế:
awk '{ print $2 " " $1}' file.txt
FS
là một lựa chọn, OFS
là một biến. ví dụawk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' |
trước khi chuyển sangawk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
Bạn cũng có thể kết hợp cut
và paste
:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
thông qua ý kiến: Có thể tránh bashism và loại bỏ một trường hợp cắt bằng cách thực hiện:
paste file.txt file.txt | cut -f2,3
cut
hoạt động tốt đối với các cột có chiều dài thay đổi miễn là bạn có một dấu tách cột duy nhất.
bash
isms và loại bỏ một ví dụ cut
bằng cách thực hiện: paste file.txt file.txt | cut -f2,3
chỉ sử dụng vỏ,
while read -r col1 col2
do
echo $col2 $col1
done <"file"
"$col2"
và "$col1"
- có thể có các siêu ký tự shell hoặc các shenanigans khác trong dữ liệu.
Bạn có thể sử dụng Perl cho điều đó:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
Ưu điểm của việc chạy perl là (nếu bạn biết Perl), bạn có thể tính toán nhiều hơn trên F so với sắp xếp lại các cột.
perl -ae print
làm việc như cat
đối với tôi
Sử dụng join
:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
Ghi chú:
-t $'\t'
Trong GNU join
sự trực quan hơn -t '\t'
mà không cần sự $
thất bại, ( coreutils v8.28 và trước đó?); nó có lẽ là một lỗi mà một cách giải quyết như $
vậy là cần thiết. Xem: unix tham gia phân tách char .
join
cần hai tên tệp, mặc dù chỉ có một tệp đang được xử lý. Sử dụng cùng tên hai lần thủ thuật join
để thực hiện hành động mong muốn.
Đối với các hệ thống có tài nguyên thấp join
cung cấp một dấu chân nhỏ hơn một số công cụ được sử dụng trong các câu trả lời khác:
wc -c $(realpath `which cut join sed awk perl`) | head -n -1
43224 /usr/bin/cut
47320 /usr/bin/join
109840 /bin/sed
658072 /usr/bin/gawk
2093624 /usr/bin/perl
Chỉ cần làm việc trên một cái gì đó rất giống nhau, tôi không phải là một chuyên gia nhưng tôi nghĩ tôi sẽ chia sẻ các lệnh tôi đã sử dụng. Tôi đã có một csv nhiều cột mà tôi chỉ yêu cầu 4 cột trong số đó và sau đó tôi cần phải sắp xếp lại chúng.
Tập tin của tôi là ống '|' phân định nhưng có thể được trao đổi.
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
Phải thừa nhận rằng nó thực sự thô và sẵn sàng nhưng nó có thể được điều chỉnh cho phù hợp!
Sử dụng sed
Sử dụng sed với các biểu thức con lồng nhau của biểu thức chính quy cơ bản để nắm bắt và sắp xếp lại nội dung cột. Cách tiếp cận này phù hợp nhất khi có một số lần cắt giới hạn để sắp xếp lại các cột, như trong trường hợp này.
Ý tưởng cơ bản là bao quanh các phần thú vị của mẫu tìm kiếm \(
và \)
, có thể được phát lại trong mẫu thay thế với \#
vị trí #
đại diện cho vị trí liên tiếp của biểu hiện phụ trong mẫu tìm kiếm.
Ví dụ:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
sản lượng:
bar foo
Văn bản bên ngoài một biểu thức con được quét nhưng không được giữ lại để phát lại trong chuỗi thay thế.
Mặc dù câu hỏi không thảo luận về các cột có chiều rộng cố định, chúng tôi sẽ thảo luận ở đây vì đây là thước đo xứng đáng cho bất kỳ giải pháp nào được đặt ra. Để đơn giản, giả sử tệp được phân cách bằng dấu cách mặc dù giải pháp có thể được mở rộng cho các dấu phân cách khác.
Sụp đổ không gian
Để minh họa cách sử dụng đơn giản nhất, giả sử rằng nhiều không gian có thể được thu gọn thành các không gian đơn và các giá trị cột thứ hai được kết thúc bằng EOL (và không được đệm không gian).
Tập tin:
bash-3.2$ cat f
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 nl
0000040 s t r 2 sp sp sp sp sp sp sp 2 nl s t r
0000060 3 sp sp sp sp sp sp sp 3 nl
0000072
Biến đổi:
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000 C o l u m n 2 sp C o l u m n 1 nl
0000020 1 sp s t r 1 nl 2 sp s t r 2 nl 3 sp
0000040 s t r 3 nl
0000045
Bảo quản chiều rộng cột
Bây giờ chúng ta hãy mở rộng phương thức thành một tệp có các cột có chiều rộng không đổi, trong khi cho phép các cột có độ rộng khác nhau.
Tập tin:
bash-3.2$ cat f2
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f2
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 sp
0000040 sp sp sp sp sp nl s t r 2 sp sp sp sp sp sp
0000060 sp 2 sp sp sp sp sp sp nl s t r 3 sp sp sp
0000100 sp sp sp sp 3 sp sp sp sp sp sp nl
0000114
Biến đổi:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r 2 sp sp sp sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Cuối cùng, mặc dù ví dụ của câu hỏi không có các chuỗi có độ dài không bằng nhau, biểu thức sed này hỗ trợ cho trường hợp này.
Tập tin:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Biến đổi:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1 str1
2 string2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r i n g 2 sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
So sánh với các phương pháp sắp xếp lại cột khác dưới vỏ
Đáng ngạc nhiên đối với một công cụ thao tác tập tin, awk không phù hợp để cắt từ một trường đến hết bản ghi. Trong sed, điều này có thể được thực hiện bằng cách sử dụng các biểu thức thông thường, ví dụ: biểu thức \(xxx.*$\)
ở đâu xxx
để khớp với cột.
Sử dụng dán và cắt các subshells trở nên khó khăn khi thực hiện các kịch bản shell. Mã hoạt động từ dòng lệnh không phân tích cú pháp khi được đưa vào trong tập lệnh shell. Ít nhất đây là kinh nghiệm của tôi (đã đưa tôi đến phương pháp này).
cut
khi không hỗ trợ lệnh đặt hàng lại trực quan này. Dù sao, một mẹo khác: bạn có thể sử dụngawk
các tùy chọn-FS
và-OFS
tùy chọn để sử dụng các dấu tách trường đầu vào và đầu ra tùy chỉnh (như-d
và--output-delimiter
chocut
).