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
そうでない場合は、1つ以上の英数字で構成される各シーケンスの最初の文字を大文字に変換できます。
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
GNUawk
とその機能を使うの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
これらの1つ(およびそれに基づいているもの)は、インスタンスではなくインスタンスになるというLingua::EN::NameCase
点で他のものとは異なります。各単語の2番目の部分に適用して同じ結果を得ることができます。é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
POSIXawk
のsh
互換性と実装があり、多くのシステム(一部のGNUではないシステムも)はGNUbash
シェルを持ち、一部のシステムにはUbuntuなどのGNU awk(一部のGNUベースのシステムではありませんが)があります。少なくともいくつかのバージョンでは、mawkを好む)。現在zsh
デフォルトでインストールされることはほとんどありません。
CentOSをGNUシステムとしてbash
以外にも提供しているgawk
場合perl
もあります。bash
gawk
sh
awk