편도 얻기 위해 주문 하강하여 연관된 인접 필드 (네 번째, 여섯 번째, 여덟 번째 또는 각각)와. 배열을 비우기 위해 delete
명령어를 사용하기 때문에 GNU awk
이 필요합니다. 오류가 발생하면 각 키를 개별적으로 삭제하려면 for
루프를 사용해야합니다.
land; road; car (blue); 1956
land; road; car (blue); 1956 ; car (yellow); 1995
land; road; car (blue); 1956 ; car (yellow); 1995; car (red); 1979
air; -; plane (black); 1984
air; -; plane (black); 1984; helicopter (red); 1998
그리고 awk
프로그램 script.awk
에서 :
BEGIN {
## Split line in ";" with spaces between it.
FS = "[[:space:]]*;[[:space:]]*";
## In output separate fields with a ";" followed by a space.
OFS = "; ";
}
## First line is special, save the line with its first two fields as a key of
## a hash to check repeated ones.
FNR == 1 {
keys[ $1 OFS $2 ] = $0;
next;
}
## For every line...
{
## Extract the key (first two fields).
key = $1 OFS $2;
## I want to get last line of each key. If it exists in the hash may be the last one, but
## can't be sure until I read the next one, so save its content, read next line and wait...
if (key in keys) {
keys[ key ] = $0;
next;
}
## Order and print vehicles by date :-)
order_and_print_vehicles_by_date(keys);
## Empty the hash.
delete keys;
## Save new kind of vehicles.
keys[ key ] = $0;
}
END {
order_and_print_vehicles_by_date(keys);
}
function order_and_print_vehicles_by_date(keys, ordered_line, dates, vehicles) {
## "keys" has only one key, get it.
for (k in keys) {
line = keys[ k ];
}
## Remove the key (first two fields) of the line.
sub(/^([^;]*;){2}[[:space:]]*/, "", line);
## Get vehicles and dates from the line.
split(line, data, /;[[:space:]]*/);
## Even positions of the array are vehicles, odd positions are for dates. Extract them.
for (i = length(data); i >= 1; i--) {
if (i % 2 == 0) {
dates[ ++d ] = data[ i ];
}
else {
vehicles[ dates[d] ] = data[ i ];
}
}
## Sort dates in descendant order.
asort(dates, ordered_dates, "@val_num_desc");
## Get the line to print.
printf "%s%s", k, OFS;
for (i = 1; i <= length(ordered_dates); i++) {
ordered_line = ordered_line sprintf("%s%s%s%s", vehicles[ ordered_dates[i] ], OFS, ordered_dates[i], OFS);
}
## Remove last ";" from the line and print.
sub(/[[:space:]]*;[[:space:]]*$/, "", ordered_line);
printf "%s\n", ordered_line;
}
실행이 좋아 : 데이터 infile
가정
awk -f script.awk infile
그 수율 :
@lqdo : 좋아. 나는 당신이 기능을 원했지만 당신의 프로그램의 모든 맥락을 모른다는 것을 읽었다. 그렇더라도, 대부분의 코드를 함수 안에 포함 시켰습니다. 'END' 섹션은 파일의 모든 입력을 읽은 후에 실행되므로 마지막 레코드를 처리하는 특별한 경우입니다. – Birei