LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices



Reply
 
Search this Thread
Old 05-18-2012, 01:52 PM   #1
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Rep: Reputation: Disabled
Help with sed and awk to change L-case letters to U-case for specific lines in a file


Hello folks. The objective is to rename all lowercase letters to uppercase letters but ONLY in certain lines of a file. Basically, Ive made some notes with commands written in them. To better read my documents, I'd like to capitalize my notes and leave the commands in the lowercase letters they already are written in.

To change all lowercase letters to uppercase letters in a document, I can use this sed command:

Code:
sed 's/\(.*\)/\U\1/' testfile
That, of course will change every letter. So what I did was I went over the document which contained 262 lines and only documented which lines I wanted to capitalize (Im sure there's no way to do this automatically unless there is a syntax with sed or awk or another program that can automatically parse commands in a file but I never heard of any).

So I made a file with just numbers in them representing each line of the document I'd like to edit like so:

17,21,25, etc

Then I realized that I don't know of a sed command to just parse those lines individually. I am aware of

Code:
sed '1,3s/\(.*\)/\U\1/' file
which will capitalize every lower case letter from lines 1-3 but I'd like to do that with just individual lines like 17,21,25,33 etc. Since I couldn't figure that one out, I know I can do

Code:
sed -e '17s/\(.*\)/\U\1/' -e '21s/\(.*\)/\U\1/' file
And that works nicely for editing those 2 lines but I have 50 lines to edit (or it can be 500 lines) and that can get old. So I'd like to be able to find a quicker way to edit my lines.

The only other thing I could think of is make a sed script and write out the numbers of the lines I want to edit in lines like so:

17
21
25

Then I was going to use
Code:
awk '{print $1 "s/\(.*\)/\U\1/"}' sedscript
Basically that would add the code
Code:
s/\(.*\)/\U\1/
to be placed right after the number with no spaces so I can use that as a sedscript but it isn't printing out like I had expected. The command line shows this output:

s/\(.*\)/\U/(strange box right here). It is missing a lot of code.
By now I could have done this all by hand but the idea is to learn it for future reference.

My sedscript already contains
#!/bin/sed -f
If I want to edit my lines, the sedscript would have to contain lines like so:
Code:
17s/\(.*\)/\U\1/
Code:
21s/\(.*\)/\U\1/
Then If I run that script against my document, it will do the job. The problem is getting the awk statement correctly to display that code. If someone could help me with that and/or the other sed command to group the editing (above the awk command) or if there is an easier way to do what I am looking for, I'd appreciate it.

Thanks,
Shawn

Last edited by rootaccess; 05-18-2012 at 01:55 PM.
 
Old 05-18-2012, 02:18 PM   #2
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,694

Rep: Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988
There is probably a quicker way in sed, but as you have the numbers in a file, simply loop through the file in a bash script and perform the sed on the corresponding lines.
Code:
for n in $(< file_with_numbers)
do
    sed "$n s/.*/\U&/" file
done
 
Old 05-18-2012, 02:58 PM   #3
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,154

Rep: Reputation: 333Reputation: 333Reputation: 333Reputation: 333
There are, of course, parsers that you could use to automatically select the lines you wish to convert to upper case. The simplest is the one you're already using - the regular expression. For more complicated things, you can use, e.g., bison to create C code that you can compile. And, of course, awk is a complete programming language.
 
Old 05-18-2012, 03:05 PM   #4
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Original Poster
Rep: Reputation: Disabled
Hi grail,

That code does not seem to work for me. I believe it is because it needs single quotes around the syntax like below. Even though the for loop is a script, it is running the sed command on the command line and not in a script and the actual syntax on the command line is:

Code:
sed '17s/.*/\U&/' file
or multiple instances of sed

Code:
sed -e '17s/.*/\U&/' -e '21s/.*/\U&/' file
and I try to put single quotes around the sed command in your script on the sed line between double quotes and it still isnt working.

It just goes through the file doing nothing.

I then add single quotes in the script around between the double quotes and I get this:
I am getting a line of this for each line
Code:
sed: -e expression #1, char 1: unknown command: `''
==================================================================
SOLVED!
EDIT:
Ok the original command did not work because it was in a script and sed usually only filters, doesnt change anything permament unless you redirect to a new file or use the -i flag. I used the -i flag and I did the syntax on the command line since I was trying everything under the sun

Code:
for n in $(< seducase);do sed -i "$n s/.*/\U&/" sed;done

Last edited by rootaccess; 05-18-2012 at 03:23 PM.
 
Old 05-18-2012, 03:20 PM   #5
pan64
Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian i686 (solaris)
Posts: 5,152

Rep: Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364
awk ' /pattern/ { print toupper ($0); next } { print } ' file
this /pattern/ { ... } can be repeated as many time you need to cover your cases. { print } will print the not covered lines
 
Old 05-18-2012, 03:25 PM   #6
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by pan64 View Post
awk ' /pattern/ { print toupper ($0); next } { print } ' file
this /pattern/ { ... } can be repeated as many time you need to cover your cases. { print } will print the not covered lines
Can you show me an example of what you are doing? This looks very useful. Are you adding a column to a file from another file? That is what I wanted to do. If anyone knows how to do that and show an example, please.

Thanks!
 
Old 05-18-2012, 03:34 PM   #7
pan64
Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian i686 (solaris)
Posts: 5,152

Rep: Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364
pattern will give you a search regexp on which lines should be affected
Code:
awk ' /pattern1/ { print toupper($0); next } # will look for pattern and makes it upcase and prints
      /pattern2/ { print toupper($0); next } # will look for another pattern and does the same
... { print }                                # this will print not affected lines unchanged 
' testfile > resultfile
this will not add column, it will generate a new file, in which all the lines selected by patterns are converted to upcase.
 
Old 05-18-2012, 03:51 PM   #8
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by pan64 View Post
pattern will give you a search regexp on which lines should be affected
Code:
awk ' /pattern1/ { print toupper($0); next } # will look for pattern and makes it upcase and prints
      /pattern2/ { print toupper($0); next } # will look for another pattern and does the same
... { print }                                # this will print not affected lines unchanged 
' testfile > resultfile
this will not add column, it will generate a new file, in which all the lines selected by patterns are converted to upcase.
I'm a bit confused. A simple example would help tremendously. Maybe output a couple lines in a file that is lowercase and only make a select few uppercase? Maybe you can show with the awk command and then cat out the files and paste them here? Would really help.

Thanks
 
Old 05-18-2012, 04:05 PM   #9
pan64
Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian i686 (solaris)
Posts: 5,152

Rep: Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364
just back to your original problem: you have a document with more than 200 lines and you want to convert some lines to upcase. Is that right? How can you select the lines?
For example (not an efficient one, but just for you): line 17, 21 and 25 should be converted.
Code:
awk ' NR == 17 { print toupper($0); next } # will look for line number 17 and makes it upcase and prints
      NR == 21 { print toupper($0); next } # 
      NR == 25 { print toupper($0); next } # 
      { print }                                # this will print not affected lines unchanged 
' yourtestfile > yourresultfile
this is not efficient, because here we look for line numbers, so we will need a lot of lines.
/pattern/ may give you a much better criteria.
 
Old 05-18-2012, 04:18 PM   #10
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by pan64 View Post
just back to your original problem: you have a document with more than 200 lines and you want to convert some lines to upcase. Is that right? How can you select the lines?
For example (not an efficient one, but just for you): line 17, 21 and 25 should be converted.
Code:
awk ' NR == 17 { print toupper($0); next } # will look for line number 17 and makes it upcase and prints
      NR == 21 { print toupper($0); next } # 
      NR == 25 { print toupper($0); next } # 
      { print }                                # this will print not affected lines unchanged 
' yourtestfile > yourresultfile
this is not efficient, because here we look for line numbers, so we will need a lot of lines.
/pattern/ may give you a much better criteria.
Ok I totally get it. WOW what a life saver. What I did was make a new file and in the /pattern/ I simply just put the word replace in the slashes since I only wanted to replace that line with all uppercase and it worked. Great stuff. Beautiful. Wondrous. Fantastique.

You're right about my way not being efficient but basically in my case, I have documents that are basically notes to all the commands I wrote down and for my notes, I only capitalized the first letter and the line below is the actual command. So it isnt very clear sometimes when scrolling down many lines. Then again in my case, unfortunately, most of the lines would have to be written down by hand and then added to the forloop script that grail created. Otherwise I may end up capitalizing letters from my commands.
 
Old 05-18-2012, 04:47 PM   #11
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Original Poster
Rep: Reputation: Disabled
Even though I have found several solutions, the quickest one (the pattern one is great but lets face it, I won't always be able to tell which exact lines will be affect and some lines I may noy want capitalized) happens to be a simple sed script

Code:
#!/bin/sed -f

s/.*/\U&/
Now what I do is, since Im eventually going to have to make a file with all the lines I want edited of a file, I might as well just load the script in vi, hit "yy" to copy the code above and then hold "p" to get that pasted down as many times as I need. Now just write the number right before the sed command in the script, so lets say I wanted lines 17,21 and 25 to be changed (and a lot more I'm sure), I just enter them so the lines look like this:

Code:
17s/.*/\U&/
21s/.*/\U&/
25s/.*/\U&/
Then if I pasted too many of these
Code:
s/.*/\U&/
, I can just hold dd until they are gone. Now ZZ and (my scripts are all in a folder which is in my $PATH) and I run it simply:
Code:
sedscript file_to_be_edited
Thanks for all the help!
Shawn
 
Old 05-18-2012, 05:22 PM   #12
rootaccess
Member
 
Registered: Mar 2012
Posts: 211

Original Poster
Rep: Reputation: Disabled
If anyone knows the syntax with awk to extract columns and paste them in another file wherever I need, I'd greatly appreciate it.

Thanks
 
Old 05-21-2012, 03:50 PM   #13
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,154

Rep: Reputation: 333Reputation: 333Reputation: 333Reputation: 333
Here's a simple program to do that. Note that this program uses the standard field separators. You could change that by setting FS in the BEGIN section or on the command line.

Code:
#!/bin/awk -f
function usage()
{
  print "Usage: replace_column -v from=number -v with=number from_file with_file out_file" > "/dev/stderr"
  print "" > "/dev/stderr"
  print "Note: This program requires that the from_file and with_file have the identical number of rows." > "/dev/stderr"
  exit(1)
}
BEGIN {
  if ((ARGC < 2) || (ARGC > 3) || (! from) ||( ! with)) usage()
  if (ARGC == 3) {out=ARGV[3];--ARGC} else {out="/sev/stdout"}
  with_file = ARGV[2]
  --ARGC
  errors=0
}
{
  if (! getline with_line < with_file) {
    if (! errors) print "Error: " FILENAME " is longer than " with_file ". No further replacements." > "/dev/stderr"
    ++errors
  }
  else {
    split(with_line, column)
  }
  if (! errors) $from = column[with]
  print > out
}
Note: Untested code.

Note2: You could get much more sophisticated by, for example, only replacing only when a line satisfies some criteria, or matches something read in the "with_file."
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
deleting lines from a file with specific pattern using AWK gandhigaurav1986 Programming 12 06-08-2010 03:08 AM
sed to remove specific lines in a file tekmann33 Linux - Newbie 3 05-21-2009 04:41 PM
Delete specific Range of lines Using sed , awk, grep etc. joyds219 Linux - Newbie 4 03-28-2008 09:59 AM
Replacing text on specific lines with sed or awk? Lantzvillian Linux - Newbie 5 10-17-2007 10:00 AM


All times are GMT -5. The time now is 12:17 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration