我正在尝试将来自名为 input.txt 的 txt 文件中每个句子中第一个单词的每个首字母大写,并且我希望此输入文件成为 shell 脚本的参数
./script.sh input.txt
示例输入文件:
i am Andrew. you are Jhon. here we are, forever.
结果文件:
I am Andrew. You are Jhon. Here we are, forever.
一个特殊的情况。如果我们的文本是(与@RaduRadeanu 答案相关)
i am andrew. you
are jhon. here we are
forever
结果是:
I am andrew. You
Are jhon. Here we are
Forever.
因此它将每个句子的第一个单词以及新行的第一个单词都转换为大写。我们如何跳过新行的第一个单词的大写?
所以正确的结果一定是:
I am andrew. You
are jhon. Here we are
forever.
如果句子以“?”或“!”结尾会怎样?
答案1
sed
命令对于从 shell 脚本编辑文件非常强大。借助它的帮助,您可以随意编辑文本文件。话虽如此,以下脚本可以满足您的要求:
#!/bin/bash
#check if a file is given as argument
if [ $# -ne 1 ];then
echo "Usage: `basename $0` FILE NAME"
exit 1
fi
sed -i 's/^\s*./\U&\E/g' $@ #capitalize first letter from a paragraf/new line
sed -i 's/[\.!?]\s*./\U&\E/g' $@ #capitalize all letters that follow a dot, ? or !
对于你的特殊情况,事情变得稍微:
#!/bin/bash
#check if a file is given as argument
if [ $# -ne 1 ];then
echo "Usage: `basename $0` FILE NAME"
exit 1
fi
sed -i '1s/^\s*./\U&\E/g' $@ #capitalize first letter from the file
sed -i 's/\.\s*./\U&\E/g' $@ #capitalize all letters that follow a dot
#check if the a line ends in dot, ? or ! character and
#if yes capitalize first letter from the next line
next_line=0
cat $@ | while read line ;do
next_line=$[$next_line+1]
lastchr=${line#${line%?}}
if [ "$lastchr" = "." ] || [ "$lastchr" = "!" ] || [ "$lastchr" = "?" ]; then
sed -i "$[$next_line+1]s/^\s*./\U&\E/g" $@
fi
done
另外,您可以参考本教程:Unix - 使用 SED 的正则表达式看看在这些情况下如何工作。
答案2
如何使用 bash 的内置“read”函数,以句点字符作为分隔符,将整个句子读入变量,然后将变量的首字符大写?例如
$ cat myfile
i am andrew. you
are jhon. here we are
forever.
$ while read -rd\. sntc; do printf "%s. " "${sntc^}"; done < myfile; printf "\n"
I am andrew. You
are jhon. Here we are
forever.
为了处理多个句子终止符(例如?和!)以及常规句号,这里是使用“awk”的另一种方法 - 请注意,允许我们恢复与特定句子匹配的特定记录终止符的 RT 变量是一个扩展,可能并非在所有“awk”版本中都可用
$ cat myfile
i am andrew? you
are jhon. here we are
forever!
$ awk 'BEGIN{RS="[.!?]+[ \t\n]*"}; {sub(".", substr(toupper($0), 1,1), $0); printf ("%s%s", $0, RT)}' myfile
I am andrew? You
are jhon. Here we are
forever!
请注意,上面的记录分隔符正则表达式将处理多个连续分隔符('!?!!!')和可选的尾随空格 - 而基于读取的版本则不会。
作为进一步的增强,让我们尝试通过再次修改 RS 正则表达式并更改子表达式,使其将第一个大写,来添加对引用句子的基本处理非引文特点:
awk 'BEGIN{RS="[.!?]+[\"'\'']?[ \t\n]*"}; {match($0, "[^\"'\'']"); sub("[^\"'\'']", substr(toupper($0),RSTART,1), $0); printf ("%s%s", $0, RT)}'
例如
$ cat myfile
i am andrew. "are
you jhon?" 'here we are
forever!?'
$ awk 'BEGIN{RS="[.!?]+[\"'\'']?[ \t\n]*"}; {match($0, "[^\"'\'']"); sub("[^\"'\'']", substr(toupper($0),RSTART,1), $0); printf ("%s%s", $0, RT)}' myfile
I am andrew. "Are
you jhon?" 'Here we are
forever!?'