무한 재귀가 발생하고 결국 스택이 너무 깊어지면 종료되는 실행 추적이 포함된 로그가 있습니다. 더 큰 라인 블록 내에 충분한 라인과 유효한 재귀가 포함되어 있어 반복되는 가장 큰 블록을 식별하기 어렵습니다. 이 결정을 내리기 위해 일부 행을 필터링해야 하는 고유한 사항은 없습니다.
파일 이름/경로 이름이 주어지면 최대 행 집합만 출력하는 좋은 한 줄/스크립트(POSIX/OS X, Linux 및 OS X에서 작동하는 것이 바람직함)는 무엇입니까?
설명: 내 예에서 로그 파일에는 432003행과 80M이 있습니다.
$ wc -l long_log.txt
432003 long_log.txt
$ du -sm long_log.txt
80 long_log.txt
비슷한 입력 파일을 만들려면 이것을 시도해 보십시오. 게시물 주셔서 감사합니다.여기임의의 단어가 포함된 파일을 만드는 방법입니다.
ruby -e 'a=STDIN.readlines;200000.times do;b=[];22.times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > head.txt
ruby -e 'a=STDIN.readlines;2.times do;b=[];22.times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > recurrence1.txt
ruby -e 'a=STDIN.readlines;20.times do;b=[];22.times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > recurrence2.txt
ruby -e 'a=STDIN.readlines;200000.times do;b=[];22.times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > tail.txt
cat head.txt recurrence1.txt recurrence1.txt recurrence2.txt recurrence1.txt recurrence1.txt recurrence2.txt recurrence1.txt tail.txt > log.txt
cat recurrence1.txt recurrence1.txt recurrence2.txt > expected.txt
결과적으로:
$ wc -l log.txt
400050 log.txt
$ du -sm log.txt
89 log.txt
그러면 다음을 수행할 수 있습니다.
$ recurrence log.txt > actual.txt
$ diff actual.txt expected.txt
$
동일한 길이의 다른 블록을 식별하는 경우에도 괜찮습니다.
$ cat recurrence1.txt recurrence2.txt recurrence1.txt recurrence1.txt recurrence2.txt recurrence1.txt > expected2.txt
$ diff actual.txt expected2.txt
$
2.6GHz 쿼드 코어 Intel Core i7과 OS X/Linux의 16GB RAM을 사용하여 10초 이내에 예상한 결과를 찾았으면 좋겠습니다.
답변1
해결책은 다음과 같습니다.TXR 언어.
@(next :args)
@(bind rangelim nil)
@(block)
@ (cases)
@filename
@ (maybe)
@rlim
@ (set rangelim @(int-str rlim))
@ (end)
@ (eof)
@ (or)
@ (output)
arguments are: filename [ range-limit ]
@ (end)
@ (fail)
@ (end)
@(end)
@(do
(defun prefix-match (list0 list1)
(let ((c 0))
(each ((l0 list0)
(l1 list1))
(if (not (equal l0 l1))
(return c))
(inc c))
c))
(defun line-stream (s)
(let (li) (gen (set li (get-line s)) li)))
(let* ((s (line-stream (open-file filename "r")))
(lim rangelim)
(s* (if lim s nil))
(h (hash :equal-based))
(max-len 0)
(max-line nil))
(for ((ln 1)) (s) ((set s (rest s)) (inc ln))
(let ((li (first s)))
(let ((po (gethash h li))) ;; prior occurences
(each ((line [mapcar car po])
(pos [mapcar cdr po]))
(let ((ml (prefix-match pos s)))
(cond ((and
(= ml (- ln line))
(> ml max-len))
(set max-len ml)
(set max-line line))))))
(pushhash h li (cons ln s))
(if (and lim (> ln lim))
(let* ((oldli (first s*))
(po (gethash h oldli))
(po* (remove-if (op eq s* (cdr @1)) po)))
(if po*
(sethash h oldli po*)
(remhash h oldli))
(set s* (cdr s*))))))
(if max-line
(format t "~a line(s) starting at line ~a\n" max-len max-line)
(format t "no repeated blocks\n"))))
이 프로그램은 거의 전적으로 TXR에 내장된 Lisp 방언으로 구성됩니다. 여기서 접근 방식은 파일의 각 줄을 해시 테이블에 저장하는 것입니다. 파일의 어느 지점에서나 우리는 해시 테이블에 "이 줄을 이전에 어디서 본 적이 있습니까?"라고 물을 수 있습니다. 그렇다면 해당 위치에서 시작하는 파일과 현재 위치에서 시작하는 줄을 비교할 수 있습니다. 일치 항목이 이전 위치에서 현재 위치까지 확장되면 이는 연속 일치가 있음을 의미합니다. 이전 위치에서 현재 줄까지의 모든 N 줄은 현재 줄부터 시작하여 N 줄과 일치합니다. 우리가 해야 할 일은 모든 후보 위치 중에서 가장 긴 일치를 생성하는 위치를 찾는 것입니다. (연결이 있는 경우 첫 번째 연결만 보고됩니다.)
보세요, Xorg 로그 파일에 두 줄이 반복적으로 나열되어 있습니다.
$ txr longseq.txr /var/log/Xorg.0.log
2 line(s) starting at line 168
168번째 줄에는 무엇이 있나요? 이 네 줄은 다음과 같습니다.
[ 19.286] (**) VBoxVideo(0): Built-in mode "VBoxDynamicMode": 56.9 MHz (scaled from 0.0 MHz), 44.3 kHz, 60.0 Hz
[ 19.286] (II) VBoxVideo(0): Modeline "VBoxDynamicMode"x0.0 56.94 1280 1282 1284 1286 732 734 736 738 (44.3 kHz)
[ 19.286] (**) VBoxVideo(0): Built-in mode "VBoxDynamicMode": 56.9 MHz (scaled from 0.0 MHz), 44.3 kHz, 60.0 Hz
[ 19.286] (II) VBoxVideo(0): Modeline "VBoxDynamicMode"x0.0 56.94 1280 1282 1284 1286 732 734 736 738 (44.3 kHz)
반면에 비밀번호 파일은 모두 고유합니다.
$ txr longseq.txr /etc/passwd
no repeated blocks
추가 두 번째 인수를 사용하여 프로그램 속도를 높일 수 있습니다. 가장 긴 반복 시퀀스가 50줄을 넘지 않는다는 것을 알고 있다면 이를 지정할 수 있습니다. 그러면 프로그램은 50줄 이상을 역추적하지 않습니다. 또한 메모리 사용량은 파일 크기가 아닌 범위 크기에 비례하므로 반대 방향으로 승리합니다.
답변2
특히 중복이 많은 경우 큰 로그에서 큰 중복 블록을 찾는 가장 빠르고 쉬운 방법은 다음과 같습니다.
sort long_log.txt | uniq -c | sort -k1n
long_log.txt는 54초가 걸렸는데, 이는 더 반복되는 작업이었습니다. 이는 제가 요청한 작업을 정확히 수행하는 스크립트의 문제인 것 같습니다. 반면 무작위로 생성된 log.txt는 47초가 걸렸습니다.
행은 순서가 지정되지 않았으며 재귀 내에 재귀가 있는 경우 행을 개별적으로 그룹화할 수 있지만(개수가 더 많을 수 있음) 이 방법의 데이터를 사용한 다음 로그로 돌아가서 관련 항목을 찾아 추출할 수도 있습니다. 부속.
.bashrc
명령은 함수로 / 에 넣을 수 있습니다 ..bash_profile
recurrence() {
sort "$1" | uniq -c | sort -k1n
}
이렇게 하면 다음과 같이 호출할 수 있습니다.
recurrence long_log.txt
답변3
이것이 bash의 솔루션입니다. 사실은 내가스크립트가 있습니다;그러나 이것이 유일한 것입니다:
find $PWD -regextype posix-extended -iregex '.*\.(php|pl)$' -type f | xargs wc -L 2> /dev/null | grep -v 'total' | sort -nrk1 | head -n 30 | awk 'BEGIN { printf "\n%-15s%s\n", "Largest Line", "File"; } { printf "%-15s%s\n", $1, $2; }'
저는 해킹된 사이트에서 해킹된 파일을 찾아 삭제할 수 있도록 이 앱을 사용합니다 -regex
.