Help with Shell Script

Hi,

I would like reading first 3 charcters from dat file and need to creat a new file based on the reading.
Assume in dat file first 3 charcters would be "abc" .that entire record needs to be extract in to a new file and remove the record from that dat file.

Regards,
KK

newname=`head -c 3 $filename`
tail -c +3 $filename > $newname
 
for i in `cat temp.txt`
do
v_substr=`expr substr "$i" 1 3`
if [ $v_substr = "abc" ]
then
echo "file contains abc"
echo $i >> file.txt
fi
done

Assuming input file is a standard format unix text file.

grep "^abc" file.txt > file_with_abc.txt
grep -v "^abc" file.txt > file_without_abc.txt

I'm not sure we have grasped the requirement here and I'm not sure if I understand it either, but I will have a go and you can tell me if I'm miles off the mark:-

whole_line=`head -1 $input_file`
data_portion="${whole_line##???}"                     # Get everything except first 3 chars
three_chars="${whole_line%$data_portion}"             # Get everything except the data portion
target_file="header_bit${three_chars}trailer_bit"     # Add anything required to build the target file name
echo $data_portion>$target_file                       # Chose overwrite or append carefully here

tail +2 $input_file > $tmp_file                       # Get record 2 and onward.  2 steps required
cat $tmp_file > $input_file                           # else you open $input_file for output
                                                      # before you have the data to write and 
                                                      # you will null the file.

I coded the string chopping in ksh internal variable commands to avoid the overhead of starting processes (cut etc.) and the IO of writing to too many temporary files. If there is a neater way to remove a record from a file, I would like to know. I did toy with:-

echo "dd:wq" | vi $input_file

...but that can run in to problems if it is a large (wide) file or contains non-displayable data. It's a problem I get annoyed at a lot.

If you are thinking of writing a loop to process the whole file, you might be better to try one of these:-

for whole_line in `cat $input_file`
do
   data_portion="${whole_line##???}"                  # Get everything except first 3 chars
   three_chars="${whole_line%$data_portion}"          # Get everything except the data portion
   target_file="header_bit${three_chars}trailer_bit"  # Add anything required to build the target file name
   echo $data_portion >> $target_file                 # Always append or you only get the last match!
done
typeset -i counter=1
total_lines=`wc -l $input_file`
while [ $counter -le $total_lines]
do
   whole_line=`sed -n ${counter}p $input_file`
   data_portion="${whole_line##???}"                  # Get everything except first 3 chars
   three_chars="${whole_line%$data_portion}"          # Get everything except the data portion
   target_file="header_bit${three_chars}trailer_bit"  # Add anything required to build the target file name
   echo $data_portion >> $target_file                 # Always append or you only get the last match!
   ((counter=$counter+1))
done

It could be sensible to truncate/remove the target files before you begin with these if you just want the output from this run. This is a neat way to acheive that:

for three_chars in `cut -c -3 $input_file|sort -u`
do
   target_file="header_bit${three_chars}trailer_bit"  # Add anything required to build the target file name
   > $target_file                                     # or substitute rm for the >
done

You could add

echo "$target_file $counter\r\c" >&2

... to get an overwriting line count as you progress. It will slow it down a bit but you should see the file name changing as the count runs. The "\r\c" will cause it to re-write the line with the next display.

There may also be a way to blend these all together

for three_chars in `cut -c -3 $input_file|sort -u`
do
   target_file="header_bit${three_chars}trailer_bit"  # Add anything required to build the target file name
   for whole_line in `grep $three_chars $input_file`
   do
      data_portion="${whole_line##???}"                  # Get everything except first 3 chars
      echo $data_portion
   done   > $target_file                  # Overwrite to negate the need to reset previous runs
done

This may give better performance from less IO and fewer processes, but perhaps the extereme could be

for three_chars in `cut -c -3 $input_file|sort -u`
do
   target_file="header_bit${three_chars}trailer_bit"  # Add anything required to build the target file name
   grep $three_chars $input_file|cut -c 3- > $target_file
done

You would have to try out the variations to see which performs best given the variety of IO, spawned proceses etc.

I hope that this is somewhere near what you are after. Apologies if I've missed the point. Code has been raw typed, so there may be snytax errors I suppose, but have a go and let me know how you get on.

Robin
Blackburn/liverpool
UK

Hi,

One 'sed' solution:

$ cat script.sed
/^abc/I {
  w newfile
}
/^abc/I! {
  p
}
$ sed -i -nf script.sed infile

Regards,
Birei

Hi All,

Thank you very much for replies.

I just need like this ...assume this is the input file contains like this below.

 
ABC ddd 343 1299 
ABC ddd 3564 1299
CDE ddd 3297 1393
CDE ddd 32989 1527
DEF ddd 346498 1652
DEF ddd 3269 1652
etc...

I need 3 out put files like this below.
out put File name1: ABC.dat

 
ABC ddd 343 1299 
ABC ddd 3564 1299

[FONT=Arial]out put File name2 : CDE .dat

[/FONT]

 
CDE ddd 3297 1393
CDE ddd 32989 1527

out put File name3 : DEF.dat

 
DEF ddd 346498 1652
DEF ddd 3269 1652

may be this one...

awk '{if($1==$1) print > $1".dat"}' inputfile

The idea is good, but since $1 is always equal to $1, it could be shortened to

awk '{print > $1".dat"}' infile 

couldn't it?

yes..thank you :smiley:

Hope this may help

 
#!/bin/ksh
oldfilename=" "
while read line
do
  filename=`echo $line | cut -c1-3`
  if [[ "$oldfilename" = "$filename" ]]
  then
    echo $line >>$oldfilename
  else
    echo $line >>$filename
  fi
  oldfilename=$filename
done <input