Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a file, that file contain 10 lines. And now I want to add 3 lines to end of the file using shell script. After add lines, If I run the script again I don't want to add same lines again.

filename : test.txt

first line : **hello this rajkumar** 
Second line: **good morningt**           
Third line : **Thank you**       
share|improve this question

closed as unclear what you're asking by slm, Anthon, Timo, Zelda, vonbrand Mar 12 at 14:43

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question.If this question can be reworded to fit the rules in the help center, please edit the question.

4 Answers 4

You can simply quote it and redirect:

% echo 'first line : **hello this rajkumar** 
        Second line: **good morningt**           
        Third line : **Thank you**' >>./file 

Or for safer handling of quotes you can concatenate a here-document with stdin and redirect stdout to your file:

% cat <<\LINES >>./file
> first line : **hello this rajkumar**
> Second line: **good morningt**
> Third line : **Thank you**
> LINES

If you want to, as I think I take your meaning, avoid writing the same line to a file twice, the following makes for a pretty quick and painless check:

% sort <<\LINES <~/file | uniq -u >>~/file
> ...
> LINES

When the -u option is specified uniq will print to its stdout only - yup, you guessed it - unique lines as read from its stdin. Kind of annoying though that it doesn't collate its input and so we need the sort utility to do so for us. I say it's annoying only because even if the compared files are in the same order already they're bound to stream in to stdin like 1,2,3,1,2,3 rather than the 1,1,2,2,3,3 it requires. Also, sort -u does almost exactly what we need except that it doesn't omit matches and so 1,2,3,4,1,2,3 becomes 1,2,3,4. Combine the two, though, and from 1,2,3.5,4,0,1,2,3 you get only 0,3.5,4.

Anyway, it gets the job done.

And then there's diff, which requires a little more configuring to print only line contents:

diff --new-group-format='%>' \
     --changed-group-format='%>' \
     --old-line-format= \
     --unchanged-line-format= \
     ~/file \
     /dev/fd/3 \
3<<\LINES >>~/file
> first line : **hello this rajkumar**
> Second line: **good morningt**
> Third line : **Thank you**
> LINES

First of all, I should mention that while it is almost certainly available for any unix you could wish, diff isn't necessarily already installed on your system. Probably it is, but maybe not.

Also, diff doesn't like stdin - it wants to read from at least two actual filesystem paths for comparison, which is why I specify the 3 redirection operator above and hand diff /dev/fd/3 as an argument.

By default diff prints a lot of information you may not necessarily want to write to your file, and that's why I demonstrate its use with all of the operands above. It does provide a --suppress-common-lines option, which is handy, but additional diff information is also included in its output and the option doesn't play nicely with arguments omitting it - so we have to specify all or none.

As shown, diff will print only the line from %> /dev/fd/3 - its rightmost file-argument - if it detects a common line between the two files has changed and only new-lines it detects from %> same. It will print nothing at all for old or unchanged lines, so appending its output to its leftmost argument - here ~/file - would result in identical behavior to the above uniq command.

share|improve this answer
    
if i run again, i dont want to add same line in a file –  rajcoumar Mar 12 at 5:49
    
So you're asking how to add a line to the end of a file only if an identical line is not already present therein? If so, I can show you, but I'm not clear on your meaning...? –  mikeserv Mar 12 at 5:53

You can append to end of a file by using >>, Example:

echo "What ever you want" >> file

IMHO, you should read bash manpage, section REDIRECTION:

Appending Redirected Output
       Redirection of output in  this  fashion  causes  the  file  whose  name
       results  from  the expansion of word to be opened for appending on file
       descriptor n, or the standard output (file descriptor 1) if  n  is  not
       specified.  If the file does not exist it is created.

       The general format for appending output is:

              [n]>>word
share|improve this answer

You can use the following construct to check if the contents of file.txt are present in another file, and if not add it.

Example

Say I have the following 2 files:

$ more file.txt afile.txt 
::::::::::::::
file.txt
::::::::::::::
first line : **hello this rajkumar**
Second line: **good morningt**
Third line : **Thank you**
::::::::::::::
afile.txt
::::::::::::::
blah
blah

Now if we use the following one liner:

$ if ! grep -qFxf file.txt afile.txt; then cat file.txt  >> afile.txt; fi

We should see lines getting added to afile.txt.

$ more afile.txt 
blah
blah
first line : **hello this rajkumar**
Second line: **good morningt**
Third line : **Thank you**

If I run the if ... one liner again we should see no changes made to afile.txt.

$ if ! grep -qFxf file.txt afile.txt; then  cat file.txt  >> afile.txt; fi
$ more afile.txt 
blah
blah
first line : **hello this rajkumar**
Second line: **good morningt**
Third line : **Thank you**

Details

The if is pretty self explanatory, the only other interesting thing going on here is the argument to if. We're looking for situations where the if statement fails, and so we're adding the contents of file.txt to afile.txt.

The switches to grep, -qFxf tell grep to be:

  • -q - quiet, don't display any matches to the grep only report them via the return status.
  • -F - Fixed strings in the file file.txt.
  • -x - Select only those matches that exactly match the whole line.
  • -f - Obtain a pattern from file file.txt.
share|improve this answer
    
There's a problem with this - and I know because I initially wrote it all up myself before testing it - grep will count as a match a line in file.txt that completely includes a line in afile.txt. This means that 'line 1 AND' in file.txt does not get added to afile.txt if it includes line 1. Even line AND 1 would be omitted. –  mikeserv Mar 12 at 8:52
    
@mikeserv - if I understand you, you're saying that if a line from file.txt is contained as a substring in a pre-existing line in afile.txt it will erroneously match? That won't happen b/c of the switches I've made use of with grep. –  slm Mar 12 at 8:57
    
I know the switches you used and - they're identical to the ones I tested, and yes it will. What's more, if one line is not in file.txt its entire contents are dumped to afile.txt. –  mikeserv Mar 12 at 9:03
    
@mikeserv - rather than us debate what the OP "might want" let's wait for him to come back and provide further details. This Q is already poorly asked and this OP has already had another Q on the site tonight heavily critiqued b/c it was lacking in details. You've provided your approach and I've provided mine. If the OP has further requirements I'm fine with sitting on this until then. I'm not going to build a yacht if all he wants is a row boat. –  slm Mar 12 at 9:11
    
You could while read it, or even (IFS="$newline" ; set -- $(cat file.txt) ; for l ; grep "$l" file ... done ) for line by line operation, but it doesn't solve the problem that grep will treat the matches inclusively and so long as any line in file.txt contains entirely a line in afile.txt it will not be added - even if it contains additional information. –  mikeserv Mar 12 at 9:14

You can also grab the last three lines of your file to a temp file and diff that with your expected lines. Append if the diff fails.

#!/bin/bash
LINES=('**hello this rajkumar**' '**good morningt**' '**Thank you**')
tail -3 afile > /tmp/afile.$$.1
printf "%s\n%s\n%s\n" "${LINES[@]}" > /tmp/afile.$$.2
if ! diff /tmp/afile.$$.1 /tmp/afile.$$.2 >/dev/null; then printf "%s\n%s\n%s\n" "${LINES[@]}" >> afile; fi
rm /tmp/afile.$$.1 /tmp/afile.$$.2
share|improve this answer

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