Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17


How to add lines into text file

Posted on 2009-07-14
Medium Priority
Last Modified: 2012-05-07
Hi, all,
I tried to insert lines and text strings into a text file using Tie::File, but had run into several obstacles. Your help is greatly appreciated!
1) the splice line of my code has caused "bad file descriptor error on my ../Tie/
2) I had hard time to find a solution that will find the dynamic line number for the seesion footer, i.e. the "Subtotal"s, which should be the next line after the  50/51...runs.
To describe the steps involved:
1) based on the first two numbers of the 2nd column, if = 50, then Salaries, if =51 then Operating...
2) insert a line before the 50 session with the label of 'Salaries' or 'Operating'... and
3) add a label on the session footer line as subtotal...
Btw, I have full control of the creation of the input file. In another words, I could make it comma delimited or tab delimited or fixed position, so the regular expression could find them.
Also, since the file is likely smaller than 1 mg, and the script will only be called occassionaly, I don't mind to have a solution that doesn't use Tie::File.

Here is the simplified input file
-----  ------ -----
xyz    50100   $100
yyy    50200  $1000
zzz    50300
abc    51200  
bbbb   51300  $123

and here is the output/modified file
-----  ------ -----
Salaries                               #<--inserted session header line
xyz    50100   $100
yyy    50200  $1000
zzz    50300      
  Subtotal Salaries $1100  #<--insterted session footer label
Operating                          #<--inserted session header line
abc    51200  
bbbb   51300  $123
  Subtotal operating $123 #<--insterted session footer label

use Tie::File;
tie(@lines, 'Tie::File', $myfile) or die "Could not open $myfile: $!\n";
if($#lines == -1) {
    print "File is empty!\n";
else {
   if (substr($_,5,2  =='50' ){
          my $new_line ="Salaries";
          splice @lines, $.+1, 0, $new_line; }
    elseif(substr($_,5,2  =='51' ){
          my $new_line ="Operating";
          splice @lines, $.+1, 0, $new_line; }<--then insert a line above it
         <--then add the same label to the end of the session
print $_."\n";   

Open in new window

Question by:ommer
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
LVL 39

Accepted Solution

Adam314 earned 800 total points
ID: 24853560
Call by giving the input and output filenames on the command line.

eg: input.txt output.txt

use strict;
use warnings;
use Data::Dumper;
die "Usage: $0 <input> <output>\n" unless $#ARGV==1;
my $input = shift;
my $output = shift;
open(my $in, "<$input") or die "Could not open '$input': $!\n";
open(my $out, ">$output") or die "Could not open '$output': $!\n";
my $state;
while(<$in>) {
	if(/\S+\s+(\d{2})/ and !defined($state)) {
		if($1 eq '50') {
			$state = 'Salaries';
		elsif($1 eq '51') {
			$state = 'Operating';
		print $out "$state\n";
	elsif(/^\s+\$\d+\s*$/ and $state) {
		s/(.*)/  Subtotal $state $1/;
		$state = undef;
	print $out $_;

Open in new window


Author Comment

ID: 24854004
Great! It works flawlessly against my test data.

However, could you give me a little more explanations on next two lines, so when I apply it to the production data, I can make right adjustments?

if(/\S+\s+(\d{2})/ and !defined($state))  

elsif(/^\s+\$\d+\s*$/ and $state)
LVL 39

Expert Comment

ID: 24854310
if(/\S+\s+(\d{2})/ and !defined($state))
If the line matches the pattern:
    \S+         1 or more non-whitespace characters
    \s+          1 or more whitespace
    (...)         Save what is in the parenthesis to the $1 variable
    \d{2}      2 digits
And the $state hasn't yet been defined (meaning, this is the first line of a new session)

elsif(/^\s+\$\d+\s*$/ and $state)
If the line matches the pattern:
    ^             start of line
    \s+          1 or more whitespace
    \$            A dollar sign.  The $ is a special character, the backslash mean an actual dollar sign
    \d+         1 or more digits
    \s*          0 or more whitespace
    $             end of line
And $state is set (meaning, the session header has been printed, it contains the session name)

Author Closing Comment

ID: 31603429

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans

704 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question