Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I am trying to capitalize each first letter of the first word in each sentence from a txt file called input.txt and I want this input file to be a argument of the shell script

 ./script.sh input.txt

sample input file:

i am Andrew. you are Jhon. here we are, forever.

result file:

I am Andrew. You are Jhon. Here we are, forever.

A special case. What if our text is (related to @RaduRadeanu answer)

i am andrew. you
are jhon. here we are
forever

the result would be:

I am andrew. You
Are jhon. Here we are
Forever.

So it convert to uppercase each first word of each sentence and also each first word of new line. How do we skip over uppercase first word of new line?

So the correct result must be:

I am andrew. You
are jhon. Here we are
forever.

What if the sentence closes in "?" or "!" ???

share|improve this question
    
You may want to read through this: stackoverflow.com/questions/2264428/… and then consider adding a regular expression to search for the period-space to determine where to modify case. –  freecode Aug 19 '13 at 15:00
    
Since you mentioned in the comments that you are using vim, would an answer that works within vim, rather than a shell script, be useful? –  evilsoup Aug 20 '13 at 7:50

2 Answers 2

up vote 3 down vote accepted

sed command is very powerful to edit files from shell scripts. With its help you can edit however you want a text file. These being said, the following script can do what you wish:

#!/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 !

For your special case, things became slightly:

#!/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

Also, you can consult this tutorial: Unix - Regular Expressions with SED to see how to work in these situations.

share|improve this answer
    
@RaduRadeanu this works great. If you have time can you please explain it to me. I will edit the question, if you want to take a look over again. –  Adrian George Aug 19 '13 at 15:09
    
@RaduRadeanu take a look over my question. I've edit it. –  Adrian George Aug 19 '13 at 15:16
    
@RaduRadeanu We should cut the following: *sed -i 's/^\s./\U&\E/g' $@ #capitalize first letter from a paragraf/new line **, right ? –  Adrian George Aug 19 '13 at 15:18
1  
@AdrianGeorge You must to put a simple condition to check if in the previous line the last character was a dot. –  Radu Rădeanu Aug 19 '13 at 15:23
    
@AdrianGeorge See the new edits. –  Radu Rădeanu Aug 19 '13 at 21:12

How about using bash's builtin 'read' function with the period character as delimiter to read each whole sentence into a variable, and then capitalizing the initial character of the variable? Something like

$ 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.

To handle multiple sentence terminators e.g. ? and ! as well as the regular period, here is a different approach using 'awk' - note that the RT variable that allows us to recover the particular record terminator which matched a particular sentence is an extension that may not be available in all varieties of '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!

Note that the record separator regex above will handle multiple consecutive delimiters ('!?!!!') and optional trailing spaces - which the read-based version doesn't.

As a further enhancement, let's try to add rudimentary handling of quoted sentences by modifying the RS regex once more and changing the sub so that it upper-cases the first non-quote character:

awk 'BEGIN{RS="[.!?]+[\"'\'']?[ \t\n]*"}; {match($0, "[^\"'\'']"); sub("[^\"'\'']", substr(toupper($0),RSTART,1), $0); printf ("%s%s", $0, RT)}'

e.g.

$ 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!?'
share|improve this answer
    
That's a very neat solution. The only issue is that it will strip leading and trailing spaces, which may or may not be a problem. –  evilsoup Aug 19 '13 at 17:57
    
Yes I couldn't think of a way around that, except for explicitly adding a single trailing space (which may not correctly reflect the original spacing) in the printf i.e. "%s ", as shown –  steeldriver Aug 19 '13 at 18:00
    
@steeldriver What if our sentence closes in "?" or "!" ? And how can I overwrite the input.txt file with the result (output) ? –  Adrian George Aug 19 '13 at 20:50
1  
@AdrianGeorge you could create a new file by surrounding the whole thing in brackets and putting a > at the end, like (while read ... done < input.txt; printf '\n') > output.txt, and then mv output.txt input.txt. The !/? problem is one that the other answer also suffers from. It's not an insurmountable problem, but extending either of these answers to cover those cases will bloat them. I think you'd be better off using a decent text editor (i.e. one with macro support, like vim or emacs). –  evilsoup Aug 19 '13 at 21:25
    
@evilsoup I am actually using vim. –  Adrian George Aug 19 '13 at 21:28

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.