7개의 필드가 있는 쉼표로 구분된 파일이 있습니다. 그러나 이러한 필드 중 하나가 ,
값에 포함됩니다. |
로 파일을 변경하지 않고 파일 구분 기호를 로 변경하고 싶습니다 ,
.
내가 가지고 있는 파일:
Name,Age,Country,ID,Address,Category,DOB
John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995
원하는 출력:
Name,Age,Country,ID,Address,Category,DOB
John Doe|19|England|3653|Manchester, England|Part Time Worker|20-05-1995
여러 가지 솔루션을 시도했지만 원하는 것을 달성하지 못했습니다. 처음 4개 열의 구분 기호만 업데이트하는 다음 명령을 시도했습니다.
sed 's/,/|/;s/,/|/;s/,/|/;s/,/|/' file
내가 찾고 있는 방법은 처음 4개 열과 마지막 2개 열의 구분 기호를 업데이트하는 것입니다. 이렇게 하면 주소 열을 변경하지 않고도 구분된 파일을 업데이트할 수 있습니다.
아래 코드를 생각해 냈는데 이렇게 하면 ,
와 사이의 내용이 제거됩니다.Manchester
England
awk '{ORS="";N=split($0,a,",");\
print a[1]"|"a[2]"|"a[3]"|"a[4]"|"; \
for(i=5;i<N-1;i++) print a[i];
print "|"a[N-1]"|"a[N] }'
답변1
당신은 awk
시도 할 수 있습니다:
awk -F, -v OFS='|' 'NR==1{print $0} NR>1{$5 = $5 FS $6; print $1,$2,$3,$4,$5,$7,$8}' file
Name,Age,Country,ID,Address,Category,DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
답변2
bash를 사용하면 주소 필드에 있는 쉼표 수에 관계없이 이를 처리할 수 있습니다.
# function to join strings with a separator
join() {
local IFS=$1
shift
printf '%s\n' "$*"
}
# process the file
{
IFS=, read -ra header
join '|' "${header[@]}"
f=${#header[@]} # expected num of fields
while IFS=, read -ra row; do
n=${#row[@]} # actual num
# with a placeholder for the address
real_row=("${row[@]:0:4}" __ "${row[@]:n-2}")
# set the actual address
real_row[4]=$(join ',' "${row[@]:4:n-f+1}")
join '|' "${real_row[@]}"
done
} < file
산출
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
답변3
어떤 쉼표를 유지하고 어떤 것을 변경해야 하는지 어떻게 아는지 설명하지 않으셨습니다. 귀하가 제공한 단일 예제 라인을 기반으로 ,
공백 뒤의 모든 내용을 다음으로 바꾸 십시오 |
.
$ sed -E 's/,(\S)/\|\1/g' file
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
또는 제목을 변경하고 싶지 않은 경우:
$ sed -E '2,${s/,(\S)/\|\1/g}' file
Name,Age,Country,ID,Address,Category,DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
또는 공백에 의존할 수 없고 대신 5번째 쉼표를 제외한 줄의 모든 쉼표를 다음과 같이 바꿔야 하는 경우에는 어떻게 될까요? "이 줄에 필드가 7개보다 많으면 ,
이 줄의 5번째 필드를 일부로 처리됨으로 바꿉니다. 4번째 필드이며 구분 기호로 사용되지 않습니다." 그렇다면 다음이 도움이 될 것입니다.
$ $ perl -F, -lane 'if($#F>6){$F[4].=",$F[5]"; splice(@F,5,1)} print join("|",@F)' file
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
또는 헤더를 변경하지 않으려면 다음을 사용하십시오.
$ perl -F, -lane 'if($#F>6){$F[4].=",$F[5]"; splice(@F,5,1)} $.==1 ? print : print join("|",@F)' file
Name,Age,Country,ID,Address,Category,DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
답변4
$ perl -F, -lne 'if ($#F == 7) {$F[4] .= ",$F[5]"; splice @F,5,1};
print join("|",@F);' input.csv
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
이 perl one-liner는 각 입력 줄에 쉼표로 구분된 필드가 몇 개 있는지 확인합니다. 필드가 8개 있는 경우 필드 4에 쉼표와 필드 5의 내용을 추가한 다음 를 사용하여 필드 5를 삭제합니다 splice()
.
@F
Perl을 사용하거나 호출할 때 awk의 $1, $2, $3 등에 해당하는 자동 분할 배열을 사용하여 이 모든 작업을 수행합니다 .-F
-a
|
그런 다음 필드 4와 5를 변경했는지 여부에 관계없이 파이프 문자로 연결된 @F 배열을 인쇄합니다 .
참고: Perl 배열은 1이 아닌 0부터 시작합니다. $#F
@F 배열의 마지막 인덱스 번호를 반환하므로 == 7
테스트가 가 아닙니다 == 8
. 8개 필드가 있는 레코드에서 @F의 인덱스는 0..7입니다. 이는 또한 5번째 필드(주소)가 $F[4]
가 아닌 로 호출된다는 의미이기도 합니다 $F[5]
.