【问题标题】:Change case of first word of each line更改每行第一个单词的大小写
【发布时间】:2017-10-19 03:17:03
【问题描述】:

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

示例输入:

hello   world  
tell    me who you are!  

示例输出:

HELLO   world  
TELL    me who you are!  

没有空行,它是 ASCII,每行以一个字母单词开头,后跟一个 制表符

使用工具:在 ma​​cOS 上的命令行上工作的任何东西(bash 3.2、BSD sed、awk、tr、perl 5、python 2.7、swift 4 等)。

【问题讨论】:

    标签: string bash awk uppercase


    【解决方案1】:

    你总是可以只使用 bash 大小写转换和一个 while 循环来完成你想要的,例如

    $ while read -r a b; do echo "${a^^} $b"; done < file
    HELLO world
    HOW are you?
    

    参数扩展 ${var^^}var 中的所有字符转换为大写,${var^} 转换第一个字母。

    Bash 3.2 - 'tr'

    对于早期的 bash,您可以使用与 tr 相同的设置并带有 herestring 来处理大小写转换:

    $ while read -r a b; do echo "$(tr [a-z] [A-Z] <<<"$a") $b"; done file
    HELLO world
    HOW are you?
    

    保留\t 字符

    要保留制表符分隔的单词,您必须在阅读过程中防止分词。不幸的是,read-d 选项不允许在一组字符上终止。检查spacestab 分隔词的一种方法是读取整行以禁用IFS= 的分词,然后向前扫描该行直到找到第一个文字$' '$'\t'。 (文字是 bash-only,不是 POSIX shell)一个简单的实现是:

    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
    

    tab 分词的输出

    HELLO   world
    HOW     are     you?
    

    【讨论】:

    • 哦,抱歉,是的,对于大小写转换扩展:),这有点早
    • @Cœur 如果出于任何原因 3.2 没有 herestring,您可以对 $(echo "$a" | tr [a-z] [A-Z]) 执行相同的操作,但最好避免使用管道。
    • 如果必须使用trsedawk 会更快。 参数扩展快如闪电,但如果您调用tr 数千次,这可能是流编辑器的工作sed...@987654345 @ 记住每个命令替换(例如$(....))和对tr 的每次调用都会产生单独的子shell。 (我会很好奇你的 time sed...time awk ... 比较...)
    • 您使用tr 的解决方案很好,但它用空格替换了制表符。
    • 是的,这是read 发生的分词 的限制。它可以通过IFS内部字段分隔符)进行控制,或者您可以通过使用字符串索引向下爬取字符串来分隔tabsspaces。你可以简单地read -r line 然后for ((i = 0; i &lt; ${#line}; i++)); do if [ "${line:$i;1}" = ' ' ] || [ "${line:$i:1}" = '\t' ]; then word="${line:0:$((i-1))}"; break; fi; done 然后简单地检查"$word" != "$line" 并在$word 上使用tr。我会在早上更新答案——太晚了:)
    【解决方案2】:

    使用awk单行:

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

    【讨论】:

    • 谢谢,它适用于后跟空格的单词。但实际上,我发现我的数据有表格而不是空格。您知道如何避免用空格替换 TAB 吗?
    • 刚刚更新了答案,以便awk 将空格和制表符都视为分隔符。
    • 好的,我终于找到了一个完全适用于我的 TAB 解决方案:awk -F$'\t' '{ OFS = "\t" } {$1 = toupper($1)}1'
    • 您可以使用-v 选项实现相同的效果 - 更新了答案。
    【解决方案3】:

    使用GNU sed:

    sed 's/^\S*/\U&/g' file
    

    \S 匹配非空白字符,\U&amp; 大写匹配的模式

    更新:如果是BSD sed,因为它不支持大多数特殊字符,它仍然可行,但需要更长的表达式

    sed -f script file
    

    脚本包含在哪里

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

    【讨论】:

    • 我认为这样做的方法很完善,sedawkbash -- 涵盖。
    • 抱歉,没有注意到它应该在 macOS 上。为BSD sedGNU sed 添加了通用方法。我同意awk 脚本在GNU sed 不可用的情况下会更干净。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-04
    • 1970-01-01
    • 2021-04-30
    相关资源
    最近更新 更多