String 更改每行第一个字的大小写

String 更改每行第一个字的大小写,string,bash,awk,uppercase,String,Bash,Awk,Uppercase,在命令行中,如何将文本文件中每行的第一个单词改为大写? 输入示例: hello world tell me who you are! 示例输出: HELLO world TELL me who you are! 没有空行,它是ASCII码,每一行都以字母开头,后跟一个选项卡 要使用的工具:任何在macOS上的命令行上工作的工具(Bash3.2、BSDSED、awk、tr、Perl5、Python2.7、swift 4等)。使用awk一行程序: awk -F

在命令行中,如何将文本文件中每行的第一个单词改为大写?

输入示例:

hello   world  
tell    me who you are!  
示例输出:

HELLO   world  
TELL    me who you are!  
没有空行,它是ASCII码,每一行都以字母开头,后跟一个选项卡


要使用的工具:任何在macOS上的命令行上工作的工具(Bash3.2、BSDSED、awk、tr、Perl5、Python2.7、swift 4等)。

使用
awk
一行程序:

awk -F$'\t' -v OFS=$'\t' '{ $1 = toupper($1) }1' file

使用
GNU sed

sed 's/^\S*/\U&/g' file
其中,
\S
匹配非空白字符,
\U&
大写匹配的模式

更新:对于
BSD sed
而言,由于它不支持大多数特殊字符,因此仍然可行,但需要更长的表达式

sed -f script file
脚本中包含

{
    h
    s/ .*//
    y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
    G
    s/\(.*\)\n[^ ]* \(.*\)/\1 \2/
}

您总是可以使用bash case转换和while循环来完成您想要的,例如

$ while read -r a b; do echo "${a^^} $b"; done < file
HELLO world
HOW are you?
保留
\t
字符

HELLO   world
HOW     are     you?
要保留制表符分隔的单词,必须防止在读取过程中拆分单词。不幸的是,
读取
-d
选项不允许在一组字符上终止。检查
空格
选项卡
分隔词的一种方法是读取整行,使用
IFS=
禁用分词,然后向前扫描整行,直到找到第一个文本
$'
$'\t'
。(文本仅限于bash,而不是posixshell)一个简单的实现是:

while IFS= read -r line; do 
    word=
    ct=0 
    for ((i = 0; i < ${#line}; i++)); do 
        ct=$i
        ## check against literal 'space' or 'tab'
        [ "${line:$i:1}" = $' ' -o "${line:$i:1}" = $'\t' ] && break 
        word="${word}${line:$i:1}"
    done
    word="$(tr [a-z] [A-Z] <<<"$word")" 
    echo "${word}${line:$((ct))}"
done <file

谢谢,它适用于后跟空格的单词。但实际上,我发现我的数据是表格而不是空格。你知道如何避免用空格替换制表符吗?只是更新了答案,以便
awk
将空格和制表符都视为分隔符。好的,我终于找到了一个完全适用于制表符的解决方案:
awk-F$'\t'{OFS=“\t”}{$1=toupper($1)}1'
您可以通过
-v
选项实现同样的效果-更新了答案。我认为这就解决了问题的方法,
sed
awk
bash
——包括在内。抱歉,没有注意到它应该出现在macOS上。为
BSD sed
GNU sed
添加了通用方法。我同意当
GNU-sed
不可用时,
awk
脚本会更干净。哦,对不起,是的,这对于案例转换扩展来说还早了一点
:)
@Cœur如果出于任何原因3.2没有herestring,您可以使用
$(echo“$a”[a-z][a-z])
,但最好避免使用管道。
sed
awk
如果必须使用
tr
会更快。参数扩展速度非常快,但是如果您要调用
tr
数千次,这可能是流编辑器
sed
的工作<代码>:)记住每个命令替换(例如,
$(..)
),并且对
tr
的每次调用都会产生单独的子shell。(我很好奇你的
时间sed…
时间awk…
比较…)你用
tr
的解决方案很好,但它用空格代替了制表符。是的,这是
读取时发生的分词限制。可以使用
IFS
(内部字段分隔符)控制,也可以通过使用字符串索引向下爬行字符串来分隔
选项卡
空格
。您可以简单地
读取-r行
,然后
for((i=0;i<${line};i++);如果[“${line:$i;1}”=''']| |[“${line:$i:1}”='\t'];然后word=“${line:0:$((i-1))}”;打破fi;完成
,然后只需选中“$word”!=“$line”
并在
$word
上使用
tr
。明天早上我会更新答案——已经很晚了。:)
HELLO   world
HOW     are     you?