누락된 값이 포함된 새 행 삽입(NA)

누락된 값이 포함된 새 행 삽입(NA)

값이 누락된 경우 텍스트 파일에 새 줄을 삽입하고 싶습니다. 예를 들어 다음 텍스트 파일(A.txt)에는 5번째 줄이 없습니다. 또한 파일에는 12줄이 있어야 하므로 11~12줄이 누락되었습니다.

1 2.30
2 3.01
3 3.22
4 3.34
6 3.01
7 2.90
8 2.99
9 3.00
10 3.02

내 예상 결과는 다음과 같습니다. 누락된 케이스의 경우 번호와 NA를 나타내는 줄을 추가해야 합니다. 보시다시피 이는 5, 11, 12행에서 예상대로 발생합니다.

1 2.30
2 3.01
3 3.22
4 3.34
5 NA
6 3.01
7 2.90
8 2.99
9 3.00
10 3.02
11 NA
12 NA

다음 스크립트를 사용하여 이 작업을 수행할 수 있습니다.

f1=/my-directory/
echo "new file" > "$f1"/newfile.txt  

for i in {1..12}; do
l=$(awk '{print $1}' /"$f1"/A.txt | grep -wE ^$i /"$f1"/A.txt)
if grep --quiet -wE ^$i /"$f1"/A.txt; then echo "$l" >> "$f1"/newfile.txt; else echo "$i NA" >> "$f1"/newfile.txt; fi

done

이것은 훌륭하게 작동합니다. 하지만 문제는 160,000줄이 넘는 줄이 포함된 약 600개의 파일에 대해 이 작업을 수행해야 한다는 것입니다. 따라서 루프 솔루션이 모든 행을 검색하는 데 너무 많은 시간이 걸립니다. 내 질문은: 이 작업을 수행하는 더 간단한 솔루션이 있습니까?

답변1

join여기서는 훌륭하게 작동합니다.

join -a 1 -o 0,2.2 -e NA  <(seq 12)  A.txt  2>/dev/null

join조인 필드가 그렇지 않으면 불평할 것이기 때문에 stderr를 버렸습니다.어휘적으로정렬되었습니다.

답변2

awk스크립트를 사용하여 이 작업을 수행할 수 있습니다 .

awk '{ while (NR + shift < $1) { print (NR + shift) " NA"; shift++ }; print } END { shift++; while (NR + shift < 13) { print (NR + shift) " NA"; shift++ } }' /tmp/test1

원하는 출력이 생성됩니다 /tmp/test1(처리하려는 각 파일로 교체).

더 읽기 쉬운 형태로:

#!/usr/bin/awk -f
{
    while (NR + shift < $1) {
        print (NR + shift) " NA"
        shift++
    }
    print
}
END {
    shift++
    while (NR + shift < 13) {
        print (NR + shift) " NA"
        shift++
    }
}

예를 들어 파일로 저장하여 fill-missing실행 가능하게 만든 다음 간단히 실행할 수 있습니다.

./fill-missing /tmp/test1

스크립트는 각 줄을 처리하고 의 현재 줄 번호에 대한 예상 증가분을 추적합니다 shift. 따라서 각 행에 대해 현재 조정된 행이 해당 행의 첫 번째 숫자와 일치하지 않으면 적절한 행 번호를 인쇄한 다음 NA행 번호가 일치하면 이를 증가시켜 현재 행을 인쇄합니다. 프로세스가 끝나면 12에 도달하는 데 필요한 모든 누락된 줄을 인쇄합니다.

답변3

awk 파일

BEGIN { i=1 ; }
function upto(x) { while (i<x) printf "%d NA\n",i++ ;}
 { if ( $1 == i ) print ; upto($1) ; i++ ;}
END { upto(final+1) ;}

으로 호출됩니다

awk -f nl.awk -v final=12 /tmp/test1

당신의 전체주기

cd /my/directory
ls | while read f
do
      awk -f ~/nl.awk -v final=12 $f > /an/other/dir/$f
done

어디

  • $HOME 디렉토리( ~/nl.awk) 에 awk 프로그램을 넣습니다.

답변4

Glenn Jackman의 bash방법 을 약간 수정하면 join이 함수는 입력 파일에서 개수를 가져오고 해당 개수를 기본값으로 사용합니다.

# Usage: inlwmv file [ missing_value [ extra_lines ] ]
#      if unset, missing_value="NA", and extra_lines=0
inlwmv() { join -a 1  -o 0,2.2  -e "${2:-NA}" \
           <(seq $((${3:-0} + $(tail -n 1 "$1" | cut -d ' ' -f1))) | sort -k 1b,1)  \
           <(sort -k 1b,1 "$1") | \
           sort -g ; }

OP 질문의 경우:

inlwmv A.file "" 2

~을 위한이 중복된 질문Jackman 버전이 마지막 값에서 실패합니다.하나의 문서, ( join정렬이 매우 까다롭지만 세 번 사용하면 sort필요에 따라 작동합니다):

inlwmv afile 0

관련 정보