목록을 정렬하고 첫 번째 열이 한 번만 나타나는 모든 행을 인쇄하는 방법을 찾고 있습니다. 즉, 첫 번째 열에서만 일치합니다. 예를 들어, 첫 번째 열이 경로이고 두 번째 열에 "type"이 포함된 파일이 있습니다.
/path/foo/1 footsy
/path/foo/1 barsy
/path/foo/X barsy
/path/bar/2 footsy
/path/bar/2 barsy
/path/foo/Y footsy
(실제 파일 정렬은 -k1,1 입니다)
이제 다음과 같은 상황을 추출하고 싶습니다.
/path/foo/X barsy
/path/foo/Y footsy
이전 행을 저장하고 이전 행의 첫 번째 필드를 현재 행의 해당 필드와 비교해야 하는 awk를 사용하는 방법을 생각하고 있습니다. 하지만 아직 어떻게 해야할지 모르겠습니다. :( 다른 질문에서 찾은 솔루션을 적용하려고 시도했지만 실제로는 원하는 대로 작동하지 않았습니다.
awk '{
prev=$0; path=$1; type=$2
getline
if ($1 != $path) {
print prev
}
}'
답변1
이러한 답변에는 입력 정렬이 필요하지 않습니다.
개수와 마지막 행을 배열에 저장합니다. 대용량 파일에는 많은 메모리가 필요하며 GNU awk가 필요합니다.
gawk '
{count[$1]++; line[$1]=$0}
END {
PROCINFO["sorted_in"]="@val_str_asc"
for (key in line) if (count[key] == 1) print line[key]
}
' file
파일을 두 번 스캔하고 먼저 개수를 얻은 다음 개수 1로 줄을 인쇄합니다.
awk 'NR == FNR {count[$1]++; next} count[$1]==1' file file
정렬된 입력을 활용하면 가장 빠르고 최소한의 메모리가 필요합니다.
awk '
prev_key && prev_key != $1 {if (count==1) print prev_line; count=0}
{prev_key=$1; prev_line=$0; count++}
END {if (count==1) print prev_line}
' file
답변2
awk
일반적으로 각 입력 줄을 읽고 해당 줄의 스크립트가 호출됩니다. 당신이 그것을 사용할 상황은getline
거의 없습니다. 다음은 6줄의 입력으로 스크립트를 실행할 때 어떤 일이 발생하는지에 대한 개요입니다.1번째 줄을 정상적으로 읽으세요
Call 변수를 설정하고getline
, 2행을 읽고
, 변수를 비교합니다.3번째 줄을 정상적으로 읽으세요
Call 변수를 설정하고getline
4행을 읽고
변수를 비교합니다.5번째 줄을 정상적으로 읽으세요
Call 변수를 설정하고getline
6행을 읽고
변수를 비교합니다.분명히 이것은 작동하지 않습니다.
둘째, 코드에서 흔히 발생하는 실수를 범하고 있습니다
awk
. 에서awk
입력의 필드는 다음으로 참조되고 변수는 다음으로 참조됩니다.$number
variable_name
. 이는 명령줄 매개변수가 로 인용되고 변수가 로 인용되는 쉘 스크립트와 다릅니다. 당신의 테스트$number
$variable_name
if ($1 != $path)
~해야 한다
if ($1 != path)
전반적인 접근 방식에 결함이 있습니다. 한 번에 두 줄을 보면 파일에 한 번만 나타나는 문자열을 식별할 수 없습니다. 나는 한 번에 세 개의 행을 보면서 이를 수행할 수 있다고 믿습니다(예:둘변수의 처음 몇 줄) 그러나 그런 것들은 복잡하고 혼란스러워집니다. 발생 횟수를 계산하는 것이 더 간단할 수 있습니다. 이렇게 하려면 스크립트를 최소한으로 수정해야 합니다.
awk '{ if ($1 != path) { if (count == 1) { print prev } count=1 } else count++ prev=$0; path=$1 } END { if (count == 1) { print prev } }'
type
사용하신 적이 없어서 삭제했습니다 .공개: 이것은 본질적으로 Glenn 답변의 마지막 부분과 동일합니다.
답변3
쉘이 지원하는 경우프로세스 교체, 공백이나 탭을 포함하지 마세요 X
.Y
$ grep -Ff <(awk '{print $1" "}' <file | LC_ALL=C uniq -u) <file
/path/foo/X barsy
/path/foo/Y footsy
답변4
다음을 사용해 볼 수 있습니다.
cat text.tx | sort | uniq -c -w11 | fgrep '1 /' | awk '{print $2" "$3}'
귀하의 text.txt는 다음과 같습니다
]#cat text.txt
/path/foo/1 footsy
/path/foo/1 barsy
/path/foo/X barsy
/path/bar/2 footsy
/path/bar/2 barsy
/path/foo/Y footsy