CentOS 시스템에 다음 입력 파일이 있습니다.
1,,,,ivan petrov,,67,
2,2,,,Vasia pupkin,director,8,
3,,,,john Lenon,,,
작업은 다음과 같이 변경하는 것입니다.
1,,,,Ivan Petrov,,67,
2,2,,,Vasia Pupkin,director,8,
3,,,,John Lenon,,,
이름은 대문자로 시작해야 합니다.
#!/bin/bash
while IFS="," read line
do
ns=$(echo $line | awk -F, '{print $5}')
name=$(echo $ns | awk '{print $1}')
surname=$(echo $ns | awk '{print $2}')
ns=$(echo ${name^} ${surname^})
awk -v nm="$ns" 'BEGIN{FS=OFS=","}{$5=nm}1' accnew.csv
done < <(tail -n +2 accnew.csv) > 1new.csv
이것은 내 스크립트이지만 제대로 작동하지 않습니다.
답변1
텍스트를 처리하기 위해 쉘 루프를 사용하지 마십시오. 텍스트 처리 유틸리티를 사용하십시오.
여기에서 5번째 필드 의 이름을 대문자로 사용 하려는 경우Lingua::EN::NameCase
perl
사용 가능한 모듈:
perl -Mopen=locale -MLingua::EN::NameCase -F, -ae '
$F[4] = nc $F[4] unless @F < 5;
print join ",", @F' < your-file
그렇지 않은 경우 대략적으로 하나 이상의 영숫자 문자로 구성된 각 시퀀스의 첫 번째 문자를 대문자로 변환할 수 있습니다.
perl -Mopen=locale -F, -ae '
$F[4] =~ s/\w+/\u$&/g unless @F < 5;
print join ",", @F' < your-file
그러나 이는 McGregor
, van Dike
...와 같은 이름이나 문자 조합을 올바르게 처리하지 못합니다.
(Perl에는 입력이 단순한 csv 이상인 경우를 대비해 적절한 CSV 구문 분석 모듈도 있습니다. 이는 예제에서 인용할 필요가 없습니다.)
표준 구문을 사용하여 동일한 작업을 수행할 수 있지만 awk
훨씬 더 번거롭습니다.
awk -F, -v OFS=, '
NF >= 5 {
r = $5; $5 = ""
while (match(r, "[[:alnum:]]+")) {
$5 = $5 substr(r, 1, RSTART - 1) \
toupper(substr(r, RSTART, 1)) \
substr(r, RSTART + 1, RLENGTH - 1)
r = substr(r, RSTART + RLENGTH)
}
$5 = $5 r
}
{print}' < your-file
GNU awk
와 그 기능을 사용하는 patsplit()
것이 약간 더 쉽습니다 .
gawk -F, -v OFS=, '
NF >= 5 {
n = patsplit($5, f, /[[:alnum:]]+/, s)
$5 = s[0]
for (i = 1; i <= n; i++)
$5 = $5 toupper(substr(f[i], 1, 1)) \
substr(f[i], 2) s[i]
}
{print}' < your-file
쉘 루프를 사용해야 한다면 최소한 대문자 연산자가 포함된 쉘을 사용하십시오:
#! /bin/zsh -
while IFS=, read -ru3 -A fields; do
(( $#fields < 5 )) || fields[5]=${(C)fields[5]}
print -r -- ${(j[,])fields} || exit
done 3< your-file
이들 중 하나(및 이를 기반으로 하는 것)는 인스턴스 가 아닌 인스턴스 Lingua::EN::NameCase
가 된다는 점에서 다른 것과 다릅니다 . 각 단어의 두 번째 부분에 적용 하여 동일한 결과를 얻을 수 있습니다 .éric serRA
Éric Serra
Éric SerRA
perl
\u
\u\L
awk
tolower()
bash
bash는 zsh 또는 ksh93에 비해 연산자가 매우 제한되어 있기 때문에 내장 명령 만 사용해야 한다면 (비효율적일 뿐만 아니라) 더 문제가 될 것입니다.read -a
구분된 값을 읽을 수 없습니다..
이는 다음과 같아야 합니다( ${var^}
연산자가 bash 4.0 이상이라고 가정).
#! /bin/bash -
set -o noglob -o nounset
IFS=,
re='^([^[:alnum:]]*)([[:alnum:]]+)(.*)$'
while IFS= read -ru3 line; do
fields=( $line'' )
if (( ${#fields[@]} >= 5 )); then
rest="${fields[4]}" fields[4]=
while [[ "$rest" =~ $re ]]; do
fields[4]="${fields[4]}${BASH_REMATCH[1]}${BASH_REMATCH[2]^}"
rest="${BASH_REMATCH[3]}"
done
fi
printf '%s\n' "${fields[*]}" || exit
done 3< your-file
이는 입력이 사용자의 로케일 문자 세트로 인코딩된 유효한 텍스트라고 가정합니다(예를 들어 UTF-8 로케일에서 위의 내용은 é
iso8859-1 또는 기타 문자 세트가 아닌 UTF-8(0xc3 0xa9 바이트)로 인코딩됩니다). bash(및 아마도 awk)는 NUL 바이트를 차단합니다.
perl
은 숫자 + 밑줄 이므로 as 가 대문자로 표시된 문자열 과 as가 대문자로 표시된 \w
문자열 간의 차이도 알 수 있습니다 . 이를 특정 입력에 맞게 조정해야 할 수도 있습니다(여기서 작업에 렌치가 추가되는 문자 결합도 고려하십시오). 또한보십시오jean_pierre
perl
Jean_pierre
Jean_Pierre
Lingua::EN::NameCase
perl
더 특별한 경우를 처리하는 모듈입니다.
기본적으로 명령이 설치되는 시스템은 무엇입니까? 대부분의 시스템에는 perl
( Text::CSV
모듈이 있을 수도 있지만 그렇지 않을 수도 있음 Lingua::EN::NameCase
) POSIX 호환성 awk
과 sh
구현이 있고, 많은 시스템(일부 GNU가 아닌 시스템도)에는 bash
GNU 쉘이 있고 일부 시스템에는 Ubuntu와 같은 GNU awk(일부 GNU 기반 시스템은 아니지만)가 있습니다. 적어도 일부 버전에서는 mawk를 선호합니다). 현재 zsh
기본적으로 설치되는 것은 거의 없습니다 .
CentOS를 GNU 시스템으로 bash
이외에도 제공 하고 있는 gawk
경우 perl
도 있습니다 .bash
gawk
sh
awk
답변2
모든 입력이 모두 영어 문자로 된 간단한 2단어 이름이고 게시한 예와 같이 중간 단어가 대문자로 표시되지 않은 경우 모든 Unix 시스템의 모든 쉘에서 awk를 사용합니다.
$ awk '
BEGIN { FS=OFS="," }
{ split($5,ns," "); $5 = uc(ns[1]) " " uc(ns[2]) }
{ print }
function uc(str) { return toupper(substr(str,1,1)) substr(str,2) }
' file
1,,,,Ivan Petrov,,67,
2,2,,,Vasia Pupkin,director,8,
3,,,,John Lenon,,,
답변3
또 다른 배쉬 방법:
while IFS=, read -ra fields; do
read -ra name <<<"${fields[4]}"
fields[4]=${name[*]^}
(IFS=,; echo "${fields[*]}")
done < file
1,,,,Ivan Petrov,,67
2,2,,,Vasia Pupkin,director,8
3,,,,John Lenon,,
그리고 펄
perl -F, -lane '
$F[4] = join " ", map {ucfirst} split " ", $F[4];
print join ",", @F;
' file
답변4
csvjson
다음에서 사용csvkitCSV 파일을 JSON으로 변환한 후 사용하세요.jq
수정된 데이터를 CSV로 내보내기 전에:
csvjson -H file |
jq -r '
.[].e |= gsub(
"(?<a>[[:alnum:]]+)";
.a | sub("(?<b>.)"; .b | ascii_upcase)) |
.[] | map(.) | @csv'
이 csvjson
명령은 CSV 파일을 JSON 문서로 변환합니다. 여기서 배열의 각 열은 알파벳 키로 정렬되며 각 원본 CSV 행에 대해 하나의 개체가 포함됩니다. 이 표현식은 각 객체에서 다섯 번째( ) 열을 선택 jq
하고 그 안에 있는 각 단어를 추출합니다. 사용된 함수는 e
각 단어의 첫 문자를 대문자로 변환한 후 그 결과를 올바르게 인용된 CSV 데이터로 출력합니다.ascii_upcase
jq
질문의 데이터를 고려하면 다음과 같은 결과가 나옵니다.
1,,,,"Ivan Petrov",,67,
2,2,,,"Vasia Pupkin","director",8,
3,,,,"John Lenon",,,
이는 삽입된 쉼표와 줄 바꿈이 포함된 CSV 필드도 처리합니다.