2013-08-27 45 views
14

Giả sử chúng ta có tệp dữ liệu này.in phần còn lại của các trường trong awk

john 32 maketing executive 
jack 41 chief technical officer 
jim 27 developer 
dela 33 assistant risk management officer 

Tôi muốn in bằng awk

john maketing executive 
jack chief technical officer 
jim developer 
dela assistant risk management officer 

Tôi biết nó có thể được thực hiện bằng for.

awk '{printf $1; for(i=3;i<NF;i++){printf " %s", $i} printf "\n"}' < file 

Vấn đề dài và phức tạp.

Có cách nào khác ngắn để in phần còn lại của các trường.

+0

Một hack đơn giản là đặt $ 2 đến "", sau đó in $ 0 (tất cả các trường) - mặc dù điều đó sẽ cung cấp cho bạn thêm dấu phân tách cho trường trống. – mkfs

+0

3 năm sau, bạn đã giúp tôi. Nhưng bạn nên thay đổi " Koreth

Trả lời

28

Set lĩnh vực (s) bạn muốn bỏ qua để trống:

awk '{$2 = ""; print $0;}' < file_name 

Nguồn: Using awk to print all columns from the nth to the last

+2

Không dọn dẹp thêm không gian và sử dụng 'print $ 0' không cần thiết có thể được thay thế bằng đơn giản' 1' – Jotne

+0

@Jotne Khi tôi sử dụng '1' tại chỗ của' in $ 0', tôi không nhận được bất kỳ đầu ra từ awk. Bạn chắc chắn chúng tương đương? – Alex

+0

không hoạt động cho bỏ trống đầu tiên – malhal

3

Bạn có thể sử dụng awk đơn giản như thế này:

awk '{$2=""}1' file 

Tuy nhiên điều này sẽ có một OFS phụ trong đầu ra của bạn có thể tránh được bằng cách này awk

awk '{sub($2 OFS, "")}1' file 

HOẶC khác bằng cách sử dụng tr và cắt giảm này kết hợp:

Trên Linux:

tr -s ' ' < file | cut -d ' ' -f1,f3- 

Ngày OSX:

tr -s ' ' < file | cut -d ' ' -f1 -f3- 
+0

Điều này sẽ là 'cut -d' '-f1,3-'. –

+0

@ AdrianFrühwirth: Cảm ơn nhưng 'cut -f1,3-' không di động và không được hỗ trợ trên OSX của tôi. – anubhava

+0

Sau đó, OSX 'cut' bị hỏng. [POSIX] (http://pubs.opengroup.org/onlinepubs/007904975/utilities/cut.html) nói rằng * Ứng dụng phải đảm bảo rằng danh sách tùy chọn-đối số (xem các tùy chọn -b, -c và -f bên dưới) là một danh sách được phân cách bằng dấu phẩy [...] * và '-f -f' ngắt trên Linux của tôi bằng' coreutils-8.16' với thông báo lỗi * cut: chỉ có thể chỉ định một loại danh sách *. –

4

này loại bỏ đệ # 2 và dọn dẹp các không gian thêm.

awk '{$2="";sub(" "," ")}1' file 
+0

Điều gì làm thêm '1' ở đây? –

+2

@ shiplu.mokadd.im Các '1' đánh giá là đúng mà đá trong khối mặc định (' {print $ 0} '). –

+0

Không làm sạch bất cứ điều gì, nhưng thay vào đó giống như tất cả các ghi đè của các lĩnh vực hiện có làm - nó thay thế 'IFS' (một hoặc nhiều liên tiếp) thành một' OFS' duy nhất. Ví dụ. đó là một cách để thực hiện bộ lọc 'bình thường hóa không gian': 'awk' {$ 1 = $ 1} 1'' –

2

Một cách khác là chỉ cần sử dụng sed để thay thế các chữ số đầu tiên và phù hợp với không gian:

sed 's|[0-9]\+\s\+||' file

8

đáng tin cậy với GNU awk cho gensub() khi sử dụng FS mặc định:

$ gawk -v delNr=2 '{$0=gensub("^([[:space:]]*([^[:space:]]+[[:space:]]+){"delNr-1"})[^[:space:]]+[[:space:]]*","\\1","")}1' file 
john maketing executive 
jack chief technical officer 
jim developer 
dela assistant risk management officer 

Với các thiết bị khác, bạn cần sử dụng match() và substr() thay vì gensub(). Lưu ý rằng delNr biến trên nói với awk mà trường bạn muốn xóa:

$ gawk -v delNr=3 '{$0=gensub("^([[:space:]]*([^[:space:]]+[[:space:]]+){"delNr-1"})[^[:space:]]+[[:space:]]*","\\1","")}1' file 
john 32 executive 
jack 41 technical officer 
jim 27 
dela 33 risk management officer 

Đừng làm điều này:

awk '{sub($2 OFS, "")}1' 

như cùng văn bản đó là trong $ 2 có thể là ở phần cuối của $ 1, và/hoặc $ 2 có thể chứa các metacharacters RE vì vậy có một cơ hội rất tốt là bạn sẽ loại bỏ chuỗi sai theo cách đó.

Đừng làm điều này:

awk '{$2=""}1' file 

vì nó cho biết thêm một FS và sẽ nén tất cả các khoảng trắng liền kề khác giữa các trường thành một char trống duy nhất mỗi.

Đừng làm điều này:

awk '{$2="";sub(" "," ")}1' file 

vì nó trách nhiệm thực hiện vấn đề không gian nén nêu trên và dựa vào một FS mã hóa cứng của một đơn trống (mặc định, tuy nhiên, như vậy có lẽ không đến nỗi tệ) nhưng quan trọng hơn nếu có không gian trước $ 1, nó sẽ loại bỏ một trong số đó thay vì không gian mà nó thêm vào giữa $ 1 và $ 2.

Điều cuối cùng đáng chú ý là trong các phiên bản gần đây của gawk có một hàm mới có tên patsplit() hoạt động như split() NHƯNG ngoài việc tạo ra một mảng các trường, nó cũng tạo ra một mảng các khoảng trắng giữa các trường. Điều đó có nghĩa là bạn có thể thao tác các trường và khoảng trắng giữa các mảng trong bảng, do đó bạn không phải lo lắng về việc awk biên dịch lại bản ghi bằng cách sử dụng OFS nếu bạn thao tác một trường. Sau đó, bạn chỉ cần in các trường bạn muốn từ các mảng. Xem patsplit() trong http://www.gnu.org/software/gawk/manual/gawk.html#String-Functions để biết thêm thông tin.

+1

câu trả lời này không phải là loại nhanh chóng và bẩn thỉu mà con người có thể học hỏi từ nó. 1 cho thông tin. – Kent

+0

Nhìn vào những biến chứng này, người ta tự hỏi liệu awk có thực sự là công cụ tốt nhất cho công việc này hay không. ví dụ. nếu các trường được phân định bằng đường ống hoặc dấu phẩy thì toàn bộ mã awk cần phải được viết lại. – anubhava

+0

Phụ thuộc vào đầu vào của bạn. Nếu bạn có các ký tự đơn giữa các trường thì 'cắt' là tốt hơn. Nếu bạn có bất cứ điều gì khác thì gawk + gensub() hoặc sed (rất tương tự cú pháp) có thể là lựa chọn tốt nhất. Cả hai đều có thể gặp vấn đề khi cố gắng mô tả sự phủ nhận của đa char REs nên bạn cần phải nhìn vào gawk + patsplit() hoặc gawk + FPAT. Không có viên đạn bạc không may. –

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