이전 줄에 줄을 추가하는 방법?


9

파싱하고 분석 해야하는 로그 파일이 있습니다. 파일은 아래와 같은 것을 포함합니다 :

파일:

20141101 server contain dump
20141101 server contain nothing
    {uekdmsam ikdas 

jwdjamc ksadkek} ssfjddkc * kdlsdl
sddsfd jfkdfk 
20141101 server contain dump

위의 시나리오를 기반으로 시작 줄에 날짜 또는 이전 줄에 추가해야하는 숫자가 포함되어 있지 않은지 확인해야합니다.

결과물 파일:

20141101 server contain dump
20141101 server contain nothing {uekdmsam ikdas jwdjamc ksadkek} ssfjddkc * kdlsdl sddsfd jfkdfk 
20141101 server contain dump

답변:


11

perl제외 예측을 사용 하는의 버전 :

$ perl -0pe 's/\n(?!([0-9]{8}|$))//g' test.txt
20141101 server contain dump
20141101 server contain nothing    {uekdmsam ikdas jwdjamc ksadkek} ssfjddkc * kdlsdlsddsfd jfkdfk
20141101 server contain dump

-0정규 표현식을 전체 파일 에서 일치시킬 수 있으며 \n(?!([0-9]{8}|$))네거티브 미리보기로 8 자리 뒤에 오는 줄 바꿈 또는 줄 끝 (와 함께 -0파일의 끝이 됨)을 의미합니다.


@terdon, 마지막 줄 바꿈을 저장하도록 업데이트되었습니다.
muru

좋은 것! 나는 당신을
공언

-0NUL로 구분 된 레코드 인 경우 아니요 . -0777전체 파일을 메모리에 넣을 때 사용 합니다 (여기서는 필요하지 않음).
Stéphane Chazelas

@ StéphaneChazelas 그렇다면 전체 파일을 읽는 것 외에 Perl을 개행 문자와 일치시키는 가장 좋은 방법은 무엇입니까?
muru

파일을 한 줄씩 처리하는 다른 답변을 참조하십시오.
Stéphane Chazelas

5

조금 쉬울 수 있습니다 sed

sed -e ':1 ; N ; $!b1' -e 's/\n\+\( *[^0-9]\)/\1/g'
  • 첫 번째 부분 :1;N;$!b1은 파일의 모든 줄 \n을 하나의 긴 줄로 나눈 값을 수집합니다

  • 두 번째 부분은 줄 바꾸기 기호가 공백이 아닌 숫자가 아닌 기호 뒤에 오는 경우 줄 바꿈 기호를 제거합니다.

메모리 제한을 피하기 위해 (특히 큰 파일의 경우) 다음을 사용할 수 있습니다.

sed -e '1{h;d}' -e '1!{/^[0-9]/!{H;d};/^[0-9]/x;$G}' -e 's/\n\+\( *[^0-9]\)/\1/g'

또는 어려운 sed대본을 잊고 그 해가 시작되는 것을 기억하십시오2

tr '\n2' ' \n' | sed -e '1!s/^/2/' -e 1{/^$/d} -e $a

좋아요, +1 작동 방식에 대한 설명을 추가해 주시겠습니까?
terdon

1
아 좋은. 나는 항상 tr '\n' $'\a' | sed $'s/\a\a*\( *[^0-9]\)/\1/g' | tr $'\a' '\n'나 자신을한다.
mirabilos

죄송합니다, GNUism 인 sed (1) 에서 POSIX BASIC REGULAR EXPRESSION S 가 아닌 것들을 사용하여 공감해야합니다.
mirabilos

1
@Costas, GNU grep의 맨 페이지입니다. POSIX BRE 사양이 있습니다 . ERE와 동등한 BRE +\{1,\}입니다. [\n]휴대용도 아닙니다. \n\{1,\}POSIX입니다.
Stéphane Chazelas

1
또한 레이블 다음에 다른 명령을 사용할 수 없습니다. POSIX seds : 1;x에서 1;x레이블 을 정의하는 것 입니다. 따라서 다음이 필요 sed -e :1 -e 'N;$!b1' -e 's/\n\{1,\}\( *[^0-9]\)/\1/g'합니다.. 또한 많은 sed구현은 패턴 공간의 크기에 대해 약간의 제한이 있습니다 (POSIX는 10 x LINE_MAX IIRC 만 보장합니다).
Stéphane Chazelas

5

한 가지 방법은 다음과 같습니다.

 $ perl -lne 's/^/\n/ if $.>1 && /^\d+/; printf "%s",$_' file
 20141101 server contain dump
 20141101 server contain nothing    {uekdmsam ikdas jwdjamc ksadkek} ssfjddkc * kdlsdlsddsfd jfkdfk 
 20141101 server contain dump

그러나 이는 최종 개행을 제거합니다. 다시 추가하려면 다음을 사용하십시오.

$ { perl -lne 's/^/\n/ if $.>1 && /^\d+/; printf "%s",$_' file; echo; } > new

설명

-l후행 줄 바꿈을 제거하고 대신 각 print호출 에 하나를 추가 하므로 printf대신 사용 합니다. 현재 행이 숫자 ( /^\d+/)로 시작 하고 현재 행 번호가 1보다 큰 경우 ( $.>1, 시작 부분에 빈 줄)을 입력하여 줄의 시작 부분에 a \n를 추가하면 printf각 줄 이 인쇄됩니다.


또는 모든 \n문자를 \0로 변경 한 다음 \0숫자 문자열 바로 앞에있는 문자를 다시 변경할 수 있습니다 \n.

$ tr '\n' '\0' < file | perl -pe 's/\0\d+ |$/\n$&/g' | tr -d '\0'
20141101 server contain dump
20141101 server contain nothing    {uekdmsam ikdas jwdjamc ksadkek} ssfjddkc * kdlsdlsddsfd jfkdfk 
20141101 server contain dump

8 개의 문자열 만 일치 시키려면 대신 다음을 사용하십시오.

$ tr '\n' '\0' < file | perl -pe 's/\0\d{8} |$/\n$&/g' | tr -d '\0'

첫 번째 인수 printf형식 입니다. 사용printf "%s", $_
Stéphane Chazelas

@ StéphaneChazelas 왜? 나는 그것이 더 깨끗하고 이해하기 쉽다는 것을 알고 있지만 보호 할 위험이 있습니까?
terdon

예, 입력에 % 문자가 포함되어 있으면 잘못되어 잠재적으로 위험합니다. %10000000000s예를 들어 입력을 사용해보십시오 .
Stéphane Chazelas

C에서, 그것은 매우 잘 알려진 매우 나쁜 습관과 취약점 소스입니다. 으로는 perl, echo %.10000000000f | perl -ne printf무릎으로 내 컴퓨터를 제공합니다.
Stéphane Chazelas

@ StéphaneChazelas 와우, 예. 내 것도. 충분히 공정한 답변을 편집하고 감사합니다.
terdon

3

사용 하여이 작업을 시도하십시오 .

#!/usr/bin/awk -f

{
    # if the current line begins with 8 digits followed by
    # 'nothing' OR the current line doesn't start with 8 digits
    if (/^[0-9]{8}.*nothing/ || !/^[0-9]{8}/) {
        # print current line without newline
        printf "%s", $0
        # feeding a 'state' variable
        weird=1
    }
    else {
        # if last line was treated in the 'if' statement
        if (weird==1) {
            printf "\n%s", $0
            weird=0
        }
        else {
            print # print the current line
        }
    }
}
END{
    print # add a newline when there's no more line to treat
}

그것을 사용하려면 :

chmod +x script.awk
./script.awk file.txt

2

terdon 알고리즘을 사용하는 또 다른 가장 간단한 방법은 (다른 대답보다) :

awk 'NR>1 && /^[0-9]{8}/{printf "%s","\n"$0;next}{printf "%s",$0}END{print}' file

ITYM END{print ""}. 대안 :awk -v ORS= 'NR>1 && /^[0-9]{8}/{print "\n"};1;END{print "\n"}'
Stéphane Chazelas


0

Le 프로그램 en bash :

while read LINE
do
    if [[ $LINE =~ ^[0-9]{8} ]]
    then
        echo -ne "\n${LINE} "
    else
        echo -n "${LINE} "
    fi
done < file.txt

한 줄 형태로 :

while read L; do if [[ $L =~ ^[0-9]{8} ]]; then echo -ne "\n${L} "; else echo -n "${L} "; fi done < file.txt

백 슬래시 ( read -r) 및 선행 공백이있는 솔루션 ( IFS=직후 while) :

while IFS= read -r LINE
do
    if [[ $LINE =~ ^[0-9]{8} ]]
    then
        echo
        echo -nE "\n${LINE} "
    else
        echo -nE "${LINE} "
    fi
done < file.txt

한 줄 양식 :

while IFS= read -r L; do if [[ $L =~ ^[0-9]{8} ]]; then echo; echo -nE "${L} "; else echo -nE "${L} "; fi done < file.text

줄에 백 슬래시와가 포함되어 있으면 중단됩니다 n. 또한 공백을 제거합니다. 그러나 mksh이것을 하기 위해 사용할 수 있습니다 :while IFS= read -r L; do [[ $L = [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]* ]] && print; print -nr -- "$L"; done; print
mirabilos

물론 모든 알고리즘이 아니라 작업에서 제공하는 요구 사항에 대한 솔루션입니다. 그것은 일반적으로 : 실제 생활에서 일어나는로 물론 최종 솔루션은 눈에 더 복잡하고 덜 읽을 수
루크

동의하지만, 실제 텍스트를 더미 텍스트로 대체하는 경우 OP ☺에 대해 너무 많이 가정하지 않는 어려운 방법을 배웠습니다.
mirabilos

0
[shyam@localhost ~]$ perl -lne 's/^/\n/ if $.>1 && /^\d+/; printf "%s",$_' appendDateText.txt

작동합니다

i/p:
##06/12/2016 20:30 Test Test Test
##TestTest
##06/12/2019 20:30 abbs  abcbcb abcbc
##06/11/2016 20:30 test test
##i123312331233123312331233123312331233123312331233Test
## 06/12/2016 20:30 abc

o/p:
##06/12/2016 20:30 Test Test TestTestTest
##06/12/2019 20:30 abbs  abcbcb abcbc
##06/11/2016 20:30 test ##testi123312331233123312331233123312331233123312331233Test
06/12/2016 20:30 abc vi appendDateText.txt 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.