I need to process a file using a shell script. The file arrives with the data as well as some embedded information releavant to how it is processed. The file is in the following format;

  • email_address
  • system_area
  • item_number
  • item_number
  • item_number
  • item_number
  • and so on ...

The email_address is required to notify the user submitting the file that it has completed and the system_area indicates to the loading process where the file should be loaded. Therefore I am taking both these values into variables for use in the script. I am currently using 3 sed commands to get the info and then remove the lines;

var1=$(sed -n '1p' infile)
var2=$(sed -n '2p' infile)
sed -i '1,2d' infile

The above code works but I feel it is 'clumsy' and probably inefficient. Does anyone know of a way to achieve the same ends more elegantly/efficiently ?

  • { read -r var1 ; read -r var2 ; } < infile Regarding 3rd command I am not sure to understand it purpose: you intend to do with remaining lines something else?
    – Costas
    Jan 29 '15 at 12:13
  • @Costas - The third line is intended to remove lines 1 and 2 from the file ready to be processed. I used sed -i to perform an 'inplace' edit. Jan 29 '15 at 12:38

Your code is quite ok, I'd probably do that as a quick solution. It's more efficient to actually exit sed immediately after printing: sed -n '1{p;q}' to avoid reading the entire file for no reason.

Now the most awkward part is reading the file twice to get first two lines. You could simply use shell builtins:

{ read -r var1; read -r var2; } < infile

and then either keep sed -i '1,2d' or simply use tail -n +3 > outfile; mv outfile infile.

The ultimate way of doing this in one single pass is to read the two variables with read and then cat the rest:

{ read -r var1; read -r var2; cat; } < infile > outfile

Note that I'm saving the output into another file (and then you can possibly copy it back). That's not as "elegant" as inplace modification with sed, but it is safer, and it does the same amount of writing. This last version also only reads the file once, not three times.

  • I like this approach but can't seem to get it to work. If I wrap the reads in {} then 'read' is not found. If I wrap in () then no errors but the assignment of the var isn't made. A straight read -r var1 < infile DOES work.Not sure what the {} does but I know that () will invoke as a sub shell. I would like to use the read method for variables with the sed for removal. It feels 'nicer'. Jan 29 '15 at 13:24
  • Which shell are you using? read is a shell builtin, it should be available from everywhere, so there must be a syntax error somewhere. Just be careful about the last semicolon inside the braces. Don't skip it, it's important. The {} syntax is just command grouping, it's not launching a new shell -- this is why the variables stay set.
    – orion
    Jan 29 '15 at 13:31
  • 1
    Thanks for the help. The problem suddenly occurred to me; you need spaces after a { and before a }. That makes it work. Jan 29 '15 at 14:50

It looks to me that var1 and var2 will get same value.

I would use

 var1=$(awk 'NR==1' infile)
 var2=$(awk 'NR==2' infile)
 sed -i '1,2d' infile


  • NR is an awk variable meaning Number of Record, that is the line number.
  • NR==1 select line 1
  • default awk action is to print the whole line

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.