Saturday, May 17, 2008

How to indent lines in text files using sed, awk, perl

Suppose I have a text file named input.txt, and I want to indent each line in the file by 5 spaces.
$ cat input.txt
12
34
56
78


The following are different ways to do the same thing:
  • sed
    $ sed  's/^/     /'  input.txt
    12
    34
    56
    78

    s/^/ / searches for the beginning of a line (^), and "replaces" that with 5 spaces.

  • awk
    $ awk  '{ print "     " $0 }'  input.txt
    12
    34
    56
    78


  • perl
    $ perl -pe  's/^/     /' input.txt
    12
    34
    56
    78

To indent a range of lines, say lines 1 to 3, inclusive:
  • sed
    $ sed  '1,3s/^/     /' input.txt
    12
    34
    56
    78

    Note that the comma specifies a range (from the line before the comma to the line after).

  • awk
    $  awk  'NR==1,NR==3 {$0 = "     "$0} {print }' input.txt
    12
    34
    56
    78

    An awk program consists of condition/action pairs. The first pair has the condition "if NR (current line number) is from 1 to 3", and the action is to append 5 spaces to $0 (the current line). The second pair has a null condition which means it applies to every line, and the action is just to print the line.

  • perl
    $ perl  -pe '$_ = "     " . $_ if  1 <= $. and $. <=3' input.txt
    12
    34
    56
    78
    $. is the current input line number. $_ is the current line. . (dot) is the concatenate operator.

Click here for another post on sed tricks.

Sunday, May 11, 2008

How to convert text files to all upper or lower case

How can you convert a text file to all lower case or all upper case?

As usual, in Linux, there are more than 1 way to accomplish a task.

To convert a file (input.txt) to all lower case (output.txt), choose any ONE of the following:

  • dd
    $ dd if=input.txt of=output.txt conv=lcase

  • tr
    $ tr '[:upper:]' '[:lower:]' < input.txt > output.txt

  • awk
    $ awk '{ print tolower($0) }' input.txt > output.txt

  • perl
    $ perl -pe '$_= lc($_)' input.txt > output.txt

  • sed
    $ sed -e 's/\(.*\)/\L\1/' input.txt > output.txt

    We use the backreference \1 to refer to the entire line and the \L to convert to lower case.


To convert a file (input.txt) to all upper case (output.txt):

  • dd
    $ dd if=input.txt of=output.txt conv=ucase

  • tr
    $ tr '[:lower:]' '[:upper:]' < input.txt > output.txt

  • awk
    $ awk '{ print toupper($0) }' input.txt > output.txt

  • perl
    $ perl -pe '$_= uc($_)' input.txt > output.txt

  • sed
    $ sed -e 's/\(.*\)/\U\1/' input.txt > output.txt


Thursday, May 8, 2008

How to prevent Linux man pages from clearing after you quit reading

Man pages are excellent resources for learning the specifics of a Linux command. After all, who can remember all the nitty gritty of a command?

One annoyance of reading man pages on some Linux distributions is that after you quit reading it, the contents are cleared off screen. The man page contents simply don't stay around after you quit man. If that happens to you, it means that the default pager for viewing man pages is the less command, and that is how less behaves.

Wiping man contents out or not is a personal preference. Some may like the man stuff being wiped out because it won't clutter up the command window. However, there are times when you want the man contents to be visible after you finish reading it. You will have that information in front of you when you enter the next command.

The good news is that you can change the man page behavior. This is done by changing the default pager from less to something like more.

[beranger-org has a great/better suggestion: instead of changing to more, use less -X]
You can change it permanently or on demand, and for everyone or just individual users. Because it is a personal preference, I would recommend changing it only for yourself.

First, you need to find out where more is.
$ which more
/bin/more


Add the following line in the .bashrc file in your home directory:
export PAGER=/bin/more 


If you want to stick with less, add this line instead.
export PAGER='less -X' 


That customizes the PAGER environment variable every time a shell process is started.

Beware that the default pager is also used in commands other than man. less is a more powerful pager than more. You may wish just to change the PAGER for the current shell session. This can be done by typing in the exact export statement above into the command line.

If you want to revert to the default PAGER (i.e., less), enter this:
$ unset PAGER


If you really insist on changing the default man behavior permanently for everyone on your system, edit the file /etc/man.config (on RedHat-based systems) or /etc/manpath.config on Debian-based systems, and change the line for PAGER. This affects only man page viewing. Alternatively, you can run update-alternatives --config pager (for Debian) or alternatives --config pager (for RedHat) to globally change the PAGER environment variable for all applications.



This is how you can control man when it exits.

Tuesday, May 6, 2008

bash quicksand 2: Quotes needed in string tests

This is part 2 of the bash quicksand series. Part 1 is about whitespaces
in variable assignment
. When you write bash shell scripts, you want to avoid these innocent-looking mistakes. We all fall into these traps at some point, especially when we first write bash scripts.

You define a bash variable, say $somevar. Later, you need to test if it is equal to some string, say "linux".

1  #!/bin/bash
...
5 if [ $somevar == "linux"]
6 then ...
9 fi
...
25 exit 0


Depending on the value of $somevar at the time of the test, you can see some puzzling errors:

  • If $somevar is null (""), then you will see this error:
    ./myscript.sh: line 5: [: =: unary operator expected

  • If $somevar has embedded spaces, e.g., "tux is great", you will see this error:
    ./myscript.sh: line 5: [: too many arguments



Now, you know this trap, don't fall into it.

A good defence is to always enclose the bash variable in quotes:
if [ "$somevar" == "linux"]
then ...
fi

Monday, May 5, 2008

How to Display Routing Table

To display the kernel routing table, you can use any of the following methods:

  • route
    $ sudo route -n
    Kernel IP routing table
    Destination Gateway Genmask Flags Metric Ref Use Iface
    192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
    0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 eth0

    You need to be root to execute route.

    The -n option means that you want numerical IP addresses displayed, instead of the corresponding host names.
  • netstat
    $ netstat -rn
    Kernel IP routing table
    Destination Gateway Genmask Flags MSS Window irtt Iface
    192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
    0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 eth0

    The -r option specifies that you want the routing table. The -n option is similar to that of the route command.
  • ip
    $ ip route list
    192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.103
    default via 192.168.0.1 dev eth0