내 임무는 원본 데이터의 코드 중 하나가 참조 목록에서 읽은 새 코드로 대체되는 목록을 만드는 것입니다. 이 경우 변경 사항은 하나만 있지만 필요한 경우 참조 목록에 더 추가할 수 있습니다.
참조 목록(mycodes)에는 다음 값이 있습니다.
100,100007
데이터는 3자리 코드의 스트림이지만 100에 대한 코드는 나머지 스트림과 함께 5자리 코드로 작성되어야 합니다. 아래와 같이 AWK 프로그램을 사용했습니다.
BEGIN{
FS=","
reffile="mycodes"
while(getline<reffile>0) {ref[$1]=$2}
}
{
val=$1
newval=ref[val]
if (newval in ref) { outval=val}
else {outval=newval}
print outval
}
입력 데이터 파일에는 다음 값이 포함됩니다.
100
101
120
130
100
프로그램이 실행될 때 올바른 출력을 생성합니다.
100007
101
120
130
10007
그러나 참조 파일의 첫 번째 항목 뒤에 공백이 있는 경우에만 작동합니다. 공백이 없으면 프로그램은 100007 이외의 다른 내용을 출력으로 생성하지 않습니다.
나는 이 AWK 프로그램의 논리에서 정확히 무슨 일이 일어나고 있는지 이해하지 못하며 누군가가 이를 설명하는 데 도움을 줄 수 있는지 궁금합니다. 특히 if (newval in ref)
.
답변1
getline
다음을 사용하여 패딩을 사용 하려면 $0
다음 방법을 참조하세요.http://awk.freeshell.org/AllAboutGetline):
while ( (getline < reffile) > 0 ) {
ref[$1] = $2
}
스크립트의 나머지 부분은 한 줄로만 구성되어야 합니다.
{ print ( $1 in ref ? ref[$1] : $1 ) }
따라서 전체 스크립트는 다음과 같습니다.
BEGIN {
FS = ","
reffile = "mycodes"
while ( (getline < reffile) > 0 ) {
ref[$1] = $2
}
}
{ print ( $1 in ref ? ref[$1] : $1 ) }
"mycodes"
파일 이름을 보관하기 위해 변수를 생성 하고 이를 매개 변수로 전달하고 싶지 않은 타당한 이유가 있다고 가정합니다 .
아니면 이렇게 할 수도 있습니다:
BEGIN { FS = "," }
NR==FNR { ref[$1] = $2; next }
{ print ( $1 in ref ? ref[$1] : $1 ) }
그리고 전화하세요. 이는 루프를 사용하여 패딩하는 것보다 약간 덜 효율적이지만 awk 'script' mycodes file
대부분의 응용 프로그램에서는 문제가 될 가능성이 없으며 분명히 더 깨끗하고 오류가 발생하기 쉬운 코드를 사용합니다.refs[]
BEGIN
getline
do 는 awk가 현재 레코드를 다시 작성하도록 강제하지 않기 때문에 print ( $1 in ref ? ref[$1] : $1 )
do 또는 이와 유사한 것보다 더 효율적이지만 if ($1 in ref) $1=ref; print $1
다시 말하지만 말이 되지 않습니다.
문제가 있기는 하지만 기존 스크립트는 설명하는 대로 실패하지 않을 수 있으며 실제 문제는 DOS 줄 끝입니다(참조https://stackoverflow.com/questions/45772525/why-does-my-tool-output-overwrite-itself-and-how-do-i-fix-it?).
답변2
val=$1
newval=ref[val]
if (newval in ref) { outval=val }
else { outval=newval }
따라서 val
기본 입력 파일에서 이러한 값을 읽습니다(예: 100
또는 123
. ref
와 같은 항목이 포함된 쌍 의 경우 키로서의 존재 여부 (즉, 요소가 존재하는지 여부 ) ref[100]=100007
를 확인할 수 있습니다 . 키(또는 요소)로 존재하는 경우에는 그렇지 않습니다 .val
ref
ref[val]
ref[val]
ref[ref[val]]
그러니 그냥 하세요 if (val in ref)
.
글쎄, 그렇다면하다newval
존재하는 경우 거기에서 발견된 값(현재 위치 ) 을 사용할 수 있습니다 .아니요, 이전 값( val
). 그러니 이렇게 해라
val=$1
newval=ref[val]
if (val in ref) { outval=newval }
else { outval=val }
@αГsнιι가 언급한 것 외에도 이제 할당 문제가 있습니다.newval=ref[val]
만들다 ref[val]
빈 문자열이 아직 존재하지 않는 경우 값으로 사용하므로 이에 대해 조치를 취해야 합니다.
완전히 제거하고 테스트 후에 만 newval
사용하십시오 .ref[val]
val=$1
# newval=ref[val] # remove this line
if (val in ref) { outval=ref[val] }
else { outval=val }
또는 거기에 두고 빈 문자열에 대해 테스트합니다.
val=$1
newval=ref[val]
if (newval != "") { outval=newval }
else { outval=val }
mycodes
두 번째 필드에 Null 값이 포함될 수 있으면 둘 사이의 차이가 의미가 있습니다.
답변3
주어진
reffile="mycodes"
while(getline<reffile>0) {ref[$1]=$2}
의 빈 행은 값이 빈 문자열이고 인덱스도 빈 문자열인 mycodes
요소를 만듭니다 .ref
그런 다음 입력 스트림을 처리할 때,
newval=ref[val]
newval
매번 $1
( 100
, 101
, 120
, ) 에는 요소가 비어 있지 않은 유일한 인덱스인 130
빈 문자열이 할당됩니다 (인덱스는 (비어 있음) 의 초기 합계 와 이후에 생성된 각 빈 요소의 인덱스 , 즉 , , ) . 이 경우 빈 문자열은 인덱스 중 하나 이므로100
ref
100
""
newval=ref[val]
101
120
130
ref
if (newval in ref) { outval=val}
else {outval=newval}
if (newval in ref)
성공하고 인쇄된 값은 입력 스트림( val
, from ) val=$1
의 현재 값 입니다.
반면 ref
에 빈 문자열로 인덱싱된 요소가 없으면(빈 줄이 없을 때 발생 mycodes
) 빈 문자열은 if (newval in ref)
매번 실패합니다. newval
그런 다음 newval
(빈 줄)이 인쇄됩니다.
두 경우 모두 yes $1
이면 100
실패 하므로 인쇄 됩니다.newval
10007
if (newval in ref)
newval
파일에 빈 줄이 없더라도 입력 스트림의 빈 줄은 동일한 수수께끼 동작을 유발할 수 있습니다 mycodes
.
귀하의 질문에서 하나 이상의 10007
, 100007
및 "5자리 코드"가 철자가 틀리고 실제로 항상 10007
(5자리 코드)를 의미한다고 가정하면 AWK 프로그램을 다음과 같이 다시 작성합니다.
awk -v FS=, '
NR == FNR {
ref[$1] = $2
next
}
($1 in ref) {
$1 = ref[$1]
}
1
' ./mycodes -
또는
awk '
BEGIN {
FS=","
while ( (getline < "mycodes") > 0 )
ref[$1] = $2
}
($1 in ref) {
$1 = ref[$1]
}
1
' -
(감사해요αГsнim실제로는 인덱스로 newval=ref[val]
추가된다는 점을 지적하므로 이는 배열에서 일치하는 인덱스를 검색하는 더 안전한 방법입니다.val
ref
($1 in ref)
답변4
주요 문제는 이 줄에 있습니다 newval=ref[val]
. 여기서 변수는 val
키 역할을 합니다( $1
에서 같음 val=$1
). 이는 실제로 를 의미합니다 newval=ref[$1]
. 이 줄에서 키가 존재하면 newval
변수의 내용이 ref[] 배열의 값으로 설정됩니다. ref[val]
그렇지 않으면 빈 값으로 설정됩니다. 즉, newval=ref[val]
키가 배열에서 발견되지 않으면 키가 null 값으로 배열에 추가되고 변경을 원하지 않을 때 향후 문제가 발생할 수 있습니다. 배열 크기/인덱스, 또는 파일이 큰 경우 사용 가능한 메모리를 초과하거나 스크립트 속도가 크게 느려질 수 있습니다.
...if-else 문에서 테스트 중이면 newval
항상 실행됩니다.else
부분.
if (newval in ref) {
outval = val; ## this section never runs
} else {
outval = newval ## this sections runs for every tests
}
newval=ref[val]
따라서 키가 행에 존재하는 한 outval
해당 키의 값이 사용되며, 그렇지 않으면 null로 설정됩니다. 에 인쇄하면 print outval
해당 키의 값이 ref[] 배열에 있으면 출력되고, 그렇지 않으면 빈 줄이 출력됩니다.
간단한 수정(추가 개선이 필요하지 않음)은 다음과 같이 줄을 변경합니다.
newval = (val in ref)?ref[val]:val
명령은 다음과 같이 작성할 수 있습니다.
$ awk 'BEGIN{ FS="," }
NR==FNR { ref[$1]=$2; next }
($1 in ref){ $1=ref[$1] }1' reference infile
100007
101
120
130
100007
$ cat reference
100,100007
$ cat infile
100
101
120
130
100