안녕하세요, 저도 이와 비슷한 문제가 있습니다우편 엽서
하지만 저는 Bash를 처음 접하고 파일이 약간 다르기 때문에 답변을 수정하여 코드에 적용할 수 없습니다.
여러 열(쉼표로 구분된 모든 열)이 있는 csv 파일이 있고 분할하려는 열은 다음과 같습니다. (입력 파일)
post_id
86680728811_272953252761568
86680728811_273859942672742
86680728811_281125741936891
86680728811_10150500662053812
_86680728811_10150500969563812
86680728811_10150501303143812
86680728811_305275689511038
_86680728811_10150501624593812
86680728811_10150501873973812
86680728811_145945585518261
두 번째 ID 번호(밑줄 다음 번호)를 추출하고 싶습니다. 일부 열은 숫자로 시작하고, 일부는 공백으로 시작하고, 일부는 "_"로 시작한다는 점을 기억하세요.
내가 원하는 출력은 각각 "_"으로 구분된 ID를 포함하는 두 개의 새 열을 추가하는 것입니다. 첫 번째 줄의 예:
page ID post ID
86680728811 272953252761568
정규식을 사용하여 숫자를 읽으려고 합니다.
awk -F',' '{print $2} /(?<=_)[0-9]+/' FB_Dataset.csv
하지만 지금까지 시도한 모든 것이 작동하지 않습니다. 어떤 제안이라도 도움이 될 것입니다. 감사해요
답변1
awk -F', *_?' -v OFS=, '
NR==1 {
for (i=1;i<=NF;i++) {
if ($i == "post_id") {
$i = "page ID" OFS "post ID";
col=$1;
};
};
print;
next
};
{
split($col,a,/_/);
$col=a[1] OFS a[2];
print;
};
' FB_Dataset.csv
표시 중인 필드 데이터가 일관되지 않은 형식(일부는 공백으로 시작하고 일부는 밑줄로 시작하고 일부는 둘 다)이므로 이 awk
스크립트는 정규식 , *_?
("쉼표 뒤에 0개 이상의 공백이 오고 선택적으로 뒤에 공백이 옴)을 사용합니다. 밑줄 ")을 필드 구분 기호( FS
)로 사용합니다.
또한 출력 필드 구분 기호( OFS
)를 쉼표로 설정합니다.
입력을 읽을 때 첫 번째 행(CSV 헤더)과 나머지 모든 행을 다르게 처리합니다.
첫 번째 줄( NR==1
)에서는 각 필드의 값을 확인하여 문자열을 찾습니다 "post_id"
. 문자열이 발견되면 필드 값을 변경하여 두 개의 새 필드 이름( page ID
및 post ID
)과 나중에 사용할 수 있도록 OFS
필드의 인덱스 번호를 변수에 저장합니다 . col
마지막으로 수정된 행을 인쇄합니다.
이는 유효한 CSV 파일에 대한 필드 이름이 고유해야 한다고 가정합니다. 여러 필드에 name 이 있으면 제대로 작동하지 않습니다 post_id
.
나머지 행의 경우 $col
밑줄( ) 문자를 구분 기호로 사용하여 필드를 배열로 분할합니다. 그런 다음 $col을 배열의 처음 두 요소로 바꾸고 수정된 행을 인쇄합니다.a
_
OFS
입력 예:
A,B,C,post_id,D,E,F
a,b,c,86680728811_272953252761568,d,e,f
a,b,c, 86680728811_273859942672742,d,e,f
a,b,c,86680728811_281125741936891,d,e,f
예제 출력:
A,B,C,page ID,post ID,D,E,F
a,b,c,86680728811,272953252761568,d,e,f
a,b,c,86680728811,273859942672742,d,e,f
a,b,c,86680728811,281125741936891,d,e,f
헤더 행에서 이 필드는 두 개의 필드( 및 ) post_id
로 변환되었으며 , CSV 데이터에서는 해당 필드가 두 개의 필드로 분할되었습니다.page ID
post ID
그런데 스크립트는 post_id
헤더 행에서 일치하는 필드 이름( )을 검색하기 때문에 분할하려는 필드 앞 및/또는 뒤의 필드 수에 관계없이 처리할 수 있습니다. 이 샘플 데이터를 통해 네 번째 필드에 우리가 원하는 이름이 포함되어 있음을 확인했습니다.col=4
$i
및 awk $col
에서는 쉘에서와 다른 의미를 갖습니다.
- 셸에서 이는 다음 변수를 의미합니다.이름예
i
그리고col
. 에서는
awk
"인덱스 번호가 변수 값과 동일한 필드의 값i
(또는 변수col
)"입니다. 즉, 간접 참조를 통해 필드에 액세스합니다.예를 들어, if
i=1
then은$i
"필드 1의 값"을 의미하며 와 동일합니다$1
.예를 들어, 필드 번호에 대해 산술 연산을 수행해야 하는 경우 유용합니다. awk에서는
NF
현재 입력 라인의 마지막 필드의 인덱스 번호를 포함하는 자동 생성 변수입니다. so 는$NF
"마지막 필드의 값"을 의미하고$(NF-1)
"마지막 필드에서 두 번째 필드의 값" 등을 의미합니다.
답변2
이것이 당신에게 효과가 있습니까? 나는 다음과 같은 형식을 가정하겠습니다.
A B C post_id
a,b,c,86680728811_272953252761568
a,b,c, 86680728811_273859942672742
a,b,c,86680728811_281125741936891
a,b,c,86680728811_10150500662053812
a,b,c,_86680728811_10150500969563812
a,b,c,86680728811_10150501303143812
a,b,c,86680728811_305275689511038
a,b,c,_86680728811_10150501624593812
a,b,c, 86680728811_10150501873973812
a,b,c,86680728811_145945585518261
그런 다음 명령
cat file | sed -Ee 's/(.*)post_id/\1page ID post I/' -e 's/,[_ ]/,/' -e 's/_/,/'
산출:
A B C page ID post ID
a,b,c,86680728811,272953252761568
a,b,c,86680728811,273859942672742
a,b,c,86680728811,281125741936891
a,b,c,86680728811,10150500662053812
a,b,c,86680728811,10150500969563812
a,b,c,86680728811,10150501303143812
a,b,c,86680728811,305275689511038
a,b,c,86680728811,10150501624593812
a,b,c,86680728811,10150501873973812
a,b,c,86680728811,145945585518261
-E
확장 정규식(GNU)을 사용하면 그룹을 캡처할 수 있습니다.
헤더를 변경하여 page ID post ID
캡처 첫 번째 그룹 (.*)
까지 추가 post_id
하고 캡처된 그룹으로 교체합니다 \1
.page ID post ID
's/(.*)post_id/\1page ID post ID/'
_
쉼표 뒤의 줄에서 선행 공백과 밑줄을 제거하고 단일 쉼표로 바꿉니다.
sed 's/,[_ ]/,/'
마지막으로 밑줄을 _
쉼표로 바꿉니다.
sed 's/_/,/'
불필요한 명령을 제거했습니다. cut
(이것은 내가 시도한 다른 명령을 상기시켜줍니다.)
답변3
나는 다음을 사용할 것이다:
awk -F' *_?' '{ print $(NF-1), $NF }' infile