I have a file that contains data like this:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc

.. --.

Question: I want to remove any line that does not start with following strings :


that means the desire output will remove all those middle unwanted dots and hashes and will look like this :

report aaaaaaaa  
-th bbbbbbbbb  
-to ccccccccc

sed/awk/grep/etc any solution that will work.


Using sed to modify the file in place:

sed -i '/^\(report\|-t\(h\|o\)\)/!d' your_file

This instructs sed to delete all lines not matching the pattern. The pattern itself is ^ (start of line), followed by either report or -t followed by either h or o.

You should note that this is not actual in-place modification: sed creates a temporary backup copy and overwrites the original file with it.

If you want sed to keep a backup copy of the original file (which might be a good idea if the file contains critical data), give the -i switch an extension to create a backup file:

sed -i'.bak' -e '/^\(report\|-t\(h\|o\)\)/!d' your_file

will modify your_file and create a backup of the original called your_file.bak.

A side note

Please don't misconstrue my intentions or take offence at this, but I've noticed that you have many similar regex/text-processing related questions. I advise you to start learning sed, awk and grep on your own to help speed up your productivity. Again, don't get me wrong, I'm all too happy to help (as are most people around here); it's just that I think that you stand to benefit hugely from picking up these tools for your daily use.

Just to prove how helpful people are around here, consider @slm's suggestion in the comments below and feel free to drop by this chatroom any time for questions.

  • 1
    Your regular expression seems unnecessarily cryptic. I think you actually use more characters than if you had just listed the three options explicitly. – nispio Nov 6 '13 at 21:59
  • 1
    @nispio I know, but it's likely to be more efficient if the file in question is large. – Joseph R. Nov 6 '13 at 22:01
  • Interesting. I have always measured regexps in terms of length or readability. I have never given much thought to execution speed. I don't think I know enough about how they are evaluated to judge what is fast, but I assume that it is implementation specific too, right? – nispio Nov 6 '13 at 22:03
  • 3
    Re-iterating what Joseph said about being willing to help, if you have general questions that don't fit in the Q&A style you can always try chatting us up in the chat room for this site. chat.stackexchange.com/rooms/26/unix-and-linux. Several of us live in there 8-) – slm Nov 6 '13 at 22:03
  • @slm Thank you for this. I will add it to my answer. – Joseph R. Nov 6 '13 at 22:08

You can use simple grep for this:

$ grep -e '^report\|^-th\|^-to' filename
  • 1
    It's not much of a savings, but you could combine the -th/-to into -t[ho]. – Kevin Nov 6 '13 at 22:47
  • grep -e or egrep – Olivier Dulac Nov 7 '13 at 8:26

Using sed:

sed -n -e '/^report\|^-th\|^-to/p' filename
  • It's not much of a savings, but you could combine the -th/-to into -t[ho]. – Kevin Nov 6 '13 at 22:47
  • 1
    @Kevin That's true. See my conversation with Joseph R. in the comments to his answer. – nispio Nov 6 '13 at 22:48

Using awk:

awk '/^report|^-t[ho]/' file
  • It's not much of a savings, but you could combine the -th/-to into -t[ho]. – Kevin Nov 6 '13 at 22:46

The questioner has made two points:

  • wanting to remove any line not starting with "report" or "-th" or "-to".
  • the desired output should remove "all those middle unwanted dots and hashes (sic)"

The solutions, at this time, address the first point and thereby also the second. But suppose the the file is larger and looks like:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc
anything else
.. --.
-tp ddd
-tq eee
     -  -----

Wouldn't addressing OP's second point do the needful?

sed -r -i.bak '/^[ |.|-]*$/d' input-file 

does the job of removing presumably unwanted lines containing just spaces, dots and dashes and retaining the rest, whatever that is.
I would think that the risk of either approach is that the nature of the file isn't properly defined.


Using Perl:

perl -ne 'print if /^report|^-t[ho]/' filename > newfile

or, to edit in place (like sed, perl will also make a temporary backup so this is not true in place editing):

perl -i.bak -ne 'print if /^report|^-t[ho]/' filename

That will make a copy of the original file called filename.bak and overwrite your original file with the edited version.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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