How to append multiple lines to a file, if these lines doesn't exist in that file?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
1
down vote

favorite












How to append multiple lines to a file, if these lines doesn't exist in that file?



For example, to add multiple global aliases to /etc/bash.bashrc I use an heredocument:



cat <<-"BASHRC" >> /etc/bash.bashrc
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"
BASHRC


I was criticized that this operation doesn't include a way to check if the lines are already there, and if mistakenly rexecute the heredocument, I could cause redundancy, as well as conflict.



Update



Please ensure not to miss the Bounty message.







share|improve this question


















  • 2




    How sure can you be that the lines in the file and the new ones are exactly the same?
    – nohillside
    Jan 13 at 10:58










  • I cannot, or maybe I can but it will be an extremely complicated mechanism.
    – Arcticooling
    Jan 13 at 11:01







  • 1




    Well, you could grep for alias rss= and only add the line of you don‘t get a match. Same for each other alias you want to add. This still doesn‘t cover situations where a user has a separate file for aliases which gets sourced by .bashrc
    – nohillside
    Jan 13 at 11:04










  • This was cross-posted at Ask Ubuntu, and I wrote an answer which was already accepted by the OP there.
    – Mukesh Sai Kumar
    Jan 13 at 11:25










  • You are quite correct @MukeshSaiKumar. Although there I asked only on aliases to find out if my approach of adding aliases is wrong. Here I desired a general one-line solution and brought aliases only as an example. But given your answer there it's likely I was wrong to publish this question here and answers should be migrated to there.
    – Arcticooling
    Jan 13 at 11:44














up vote
1
down vote

favorite












How to append multiple lines to a file, if these lines doesn't exist in that file?



For example, to add multiple global aliases to /etc/bash.bashrc I use an heredocument:



cat <<-"BASHRC" >> /etc/bash.bashrc
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"
BASHRC


I was criticized that this operation doesn't include a way to check if the lines are already there, and if mistakenly rexecute the heredocument, I could cause redundancy, as well as conflict.



Update



Please ensure not to miss the Bounty message.







share|improve this question


















  • 2




    How sure can you be that the lines in the file and the new ones are exactly the same?
    – nohillside
    Jan 13 at 10:58










  • I cannot, or maybe I can but it will be an extremely complicated mechanism.
    – Arcticooling
    Jan 13 at 11:01







  • 1




    Well, you could grep for alias rss= and only add the line of you don‘t get a match. Same for each other alias you want to add. This still doesn‘t cover situations where a user has a separate file for aliases which gets sourced by .bashrc
    – nohillside
    Jan 13 at 11:04










  • This was cross-posted at Ask Ubuntu, and I wrote an answer which was already accepted by the OP there.
    – Mukesh Sai Kumar
    Jan 13 at 11:25










  • You are quite correct @MukeshSaiKumar. Although there I asked only on aliases to find out if my approach of adding aliases is wrong. Here I desired a general one-line solution and brought aliases only as an example. But given your answer there it's likely I was wrong to publish this question here and answers should be migrated to there.
    – Arcticooling
    Jan 13 at 11:44












up vote
1
down vote

favorite









up vote
1
down vote

favorite











How to append multiple lines to a file, if these lines doesn't exist in that file?



For example, to add multiple global aliases to /etc/bash.bashrc I use an heredocument:



cat <<-"BASHRC" >> /etc/bash.bashrc
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"
BASHRC


I was criticized that this operation doesn't include a way to check if the lines are already there, and if mistakenly rexecute the heredocument, I could cause redundancy, as well as conflict.



Update



Please ensure not to miss the Bounty message.







share|improve this question














How to append multiple lines to a file, if these lines doesn't exist in that file?



For example, to add multiple global aliases to /etc/bash.bashrc I use an heredocument:



cat <<-"BASHRC" >> /etc/bash.bashrc
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"
BASHRC


I was criticized that this operation doesn't include a way to check if the lines are already there, and if mistakenly rexecute the heredocument, I could cause redundancy, as well as conflict.



Update



Please ensure not to miss the Bounty message.









share|improve this question













share|improve this question




share|improve this question








edited Jan 17 at 14:04

























asked Jan 13 at 10:45









Arcticooling

83123




83123







  • 2




    How sure can you be that the lines in the file and the new ones are exactly the same?
    – nohillside
    Jan 13 at 10:58










  • I cannot, or maybe I can but it will be an extremely complicated mechanism.
    – Arcticooling
    Jan 13 at 11:01







  • 1




    Well, you could grep for alias rss= and only add the line of you don‘t get a match. Same for each other alias you want to add. This still doesn‘t cover situations where a user has a separate file for aliases which gets sourced by .bashrc
    – nohillside
    Jan 13 at 11:04










  • This was cross-posted at Ask Ubuntu, and I wrote an answer which was already accepted by the OP there.
    – Mukesh Sai Kumar
    Jan 13 at 11:25










  • You are quite correct @MukeshSaiKumar. Although there I asked only on aliases to find out if my approach of adding aliases is wrong. Here I desired a general one-line solution and brought aliases only as an example. But given your answer there it's likely I was wrong to publish this question here and answers should be migrated to there.
    – Arcticooling
    Jan 13 at 11:44












  • 2




    How sure can you be that the lines in the file and the new ones are exactly the same?
    – nohillside
    Jan 13 at 10:58










  • I cannot, or maybe I can but it will be an extremely complicated mechanism.
    – Arcticooling
    Jan 13 at 11:01







  • 1




    Well, you could grep for alias rss= and only add the line of you don‘t get a match. Same for each other alias you want to add. This still doesn‘t cover situations where a user has a separate file for aliases which gets sourced by .bashrc
    – nohillside
    Jan 13 at 11:04










  • This was cross-posted at Ask Ubuntu, and I wrote an answer which was already accepted by the OP there.
    – Mukesh Sai Kumar
    Jan 13 at 11:25










  • You are quite correct @MukeshSaiKumar. Although there I asked only on aliases to find out if my approach of adding aliases is wrong. Here I desired a general one-line solution and brought aliases only as an example. But given your answer there it's likely I was wrong to publish this question here and answers should be migrated to there.
    – Arcticooling
    Jan 13 at 11:44







2




2




How sure can you be that the lines in the file and the new ones are exactly the same?
– nohillside
Jan 13 at 10:58




How sure can you be that the lines in the file and the new ones are exactly the same?
– nohillside
Jan 13 at 10:58












I cannot, or maybe I can but it will be an extremely complicated mechanism.
– Arcticooling
Jan 13 at 11:01





I cannot, or maybe I can but it will be an extremely complicated mechanism.
– Arcticooling
Jan 13 at 11:01





1




1




Well, you could grep for alias rss= and only add the line of you don‘t get a match. Same for each other alias you want to add. This still doesn‘t cover situations where a user has a separate file for aliases which gets sourced by .bashrc
– nohillside
Jan 13 at 11:04




Well, you could grep for alias rss= and only add the line of you don‘t get a match. Same for each other alias you want to add. This still doesn‘t cover situations where a user has a separate file for aliases which gets sourced by .bashrc
– nohillside
Jan 13 at 11:04












This was cross-posted at Ask Ubuntu, and I wrote an answer which was already accepted by the OP there.
– Mukesh Sai Kumar
Jan 13 at 11:25




This was cross-posted at Ask Ubuntu, and I wrote an answer which was already accepted by the OP there.
– Mukesh Sai Kumar
Jan 13 at 11:25












You are quite correct @MukeshSaiKumar. Although there I asked only on aliases to find out if my approach of adding aliases is wrong. Here I desired a general one-line solution and brought aliases only as an example. But given your answer there it's likely I was wrong to publish this question here and answers should be migrated to there.
– Arcticooling
Jan 13 at 11:44




You are quite correct @MukeshSaiKumar. Although there I asked only on aliases to find out if my approach of adding aliases is wrong. Here I desired a general one-line solution and brought aliases only as an example. But given your answer there it's likely I was wrong to publish this question here and answers should be migrated to there.
– Arcticooling
Jan 13 at 11:44










5 Answers
5






active

oldest

votes

















up vote
2
down vote



accepted
+50










Simple shell script to add lines from the file newdata to datafile. It should be straightforward to change newdata to a here-doc. This is really not very effective since it calls grep for every (new) input line:



target=datafile
while IFS= read -r line ; do
if ! grep -Fqxe "$line" "$target" ; then
printf "%sn" "$line" >> "$target"
fi
done < newdata


For each line, we use grep to see if it already exists in the target file, -F for fixed-string match (no regexes), -x for full line match, and -q to suppress output of matched lines. grep returns a falsy error code if it doesn't find a matching line, so append to target file if the negated result is truthy.




More effectively, in awk. This relies on awk being able handle arbitrary lines as keys to an array.



$ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata 


The first part FNR == NR lines[$0] = 1; next loads all lines of the first input file as keys into the (associative) array lines. The second part ! ($0 in lines) print runs on following input lines, and prints the line if it's not in the array, i.e. the "new" lines.



The resulting output contains the new lines, only, so it needs to be appended to the original file, e.g. with sponge:



$ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata | sponge -a datafile


Or we could have awk append the lines to the final line, it just requires passing the file name to awk:



$ target=datafile 
$ awk -vtarget="$target" 'FNR == NR lines[$0] = 1; next
! ($0 in lines) print >> target' "$target" newdata


To use a here-doc with awk, we'll need to add - (stdin) as an explicit source file, in addition to setting the redirection, so awk ... "$target" - <<EOF






share|improve this answer





























    up vote
    3
    down vote













    This solution is probably a little different than what you had in mind but I'd check whether an alias is actually defined and only add it to bashrc if it isn't. Assuming you are using a relatively current version of Bash...



    # instead of 'alias x=y' form put them in an associative array
    declare -A aliases
    aliases['a']='apple'
    aliases['ba']='banana'

    for key in "$!aliases[@]"; do
    if ! alias "$key" > /dev/null 2>&1; then
    printf "alias %s='%s'n" "$key" "$aliases[$key]" >> /etc/bash.bashrc
    fi
    done

    unset aliases key


    Source this . ./scriptname rather than run it as a normal script.



    Note: If you have a bunch of the candidate aliases and are wary of manually converting them to associative array form then you c edit the file with vim and run this commmand: :%s/valias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/.



    OR put your candidate aliases (and nothing else) in a file (e.g. /tmp/aliases.txt) and replace the aliases[..]='..' lines in the script with this:



    while IFS= read -r a; do 
    eval "$a";
    done < <(sed -E "s/alias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/" /tmp/aliases.txt)


    Of course, there are other ways besides using AAs but they're clean and easy to work with...and I'm all in at this point. :)






    share|improve this answer





























      up vote
      1
      down vote













      A generic solution for exact matches (not optimized for performance); the file input contains the lines to be checked for:



      awk 'FNR==NR lines[NR]=$0; next; ;
      for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; ;
      END for(i=1;i<=length(lines);i++)
      if (matches[i]==0) print lines[i]; ' input file


      Testing:



      :> cat input
      alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
      alias brc="nano /etc/bash.bashrc"

      :> cat file
      a
      b
      c
      alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
      d


      Output of the awk command:



      a
      b
      c
      alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
      d
      alias brc="nano /etc/bash.bashrc"





      share|improve this answer



























        up vote
        0
        down vote













        Does the order of appended lines matter?



        If no, you can try such a solution:



        comm -1 -3 <(sort /etc/bash.bashrc) <(sort aliases) >> /etc/bash.bashrc


        assuming you have previously saved lines to add in the file aliases.



        comm is GNU coreutil (you can see the man page for it), which allows comparing two sorted files line by line.






        share|improve this answer



























          up vote
          0
          down vote













          Hmmmm. How about this...



          Put the aliases to add in file new. Then...



          cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp


          We unique sort both the new aliases and the bashrc contents (put in a temp file to avoid race condition when we append to bashrc) and run them through comm. comm does line-by-line comparisons of sorted files and shows unique and common lines. We suppress columns 2 and 3 (-23) so the result is simply those lines that are unique to new and we append those to bashrc. That's it.



          (This is a totally different approach than my other answer, focusing on your quest for more of a "one-liner".)






          share|improve this answer






















            Your Answer







            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "106"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f416786%2fhow-to-append-multiple-lines-to-a-file-if-these-lines-doesnt-exist-in-that-fil%23new-answer', 'question_page');

            );

            Post as a guest






























            5 Answers
            5






            active

            oldest

            votes








            5 Answers
            5






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            2
            down vote



            accepted
            +50










            Simple shell script to add lines from the file newdata to datafile. It should be straightforward to change newdata to a here-doc. This is really not very effective since it calls grep for every (new) input line:



            target=datafile
            while IFS= read -r line ; do
            if ! grep -Fqxe "$line" "$target" ; then
            printf "%sn" "$line" >> "$target"
            fi
            done < newdata


            For each line, we use grep to see if it already exists in the target file, -F for fixed-string match (no regexes), -x for full line match, and -q to suppress output of matched lines. grep returns a falsy error code if it doesn't find a matching line, so append to target file if the negated result is truthy.




            More effectively, in awk. This relies on awk being able handle arbitrary lines as keys to an array.



            $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata 


            The first part FNR == NR lines[$0] = 1; next loads all lines of the first input file as keys into the (associative) array lines. The second part ! ($0 in lines) print runs on following input lines, and prints the line if it's not in the array, i.e. the "new" lines.



            The resulting output contains the new lines, only, so it needs to be appended to the original file, e.g. with sponge:



            $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata | sponge -a datafile


            Or we could have awk append the lines to the final line, it just requires passing the file name to awk:



            $ target=datafile 
            $ awk -vtarget="$target" 'FNR == NR lines[$0] = 1; next
            ! ($0 in lines) print >> target' "$target" newdata


            To use a here-doc with awk, we'll need to add - (stdin) as an explicit source file, in addition to setting the redirection, so awk ... "$target" - <<EOF






            share|improve this answer


























              up vote
              2
              down vote



              accepted
              +50










              Simple shell script to add lines from the file newdata to datafile. It should be straightforward to change newdata to a here-doc. This is really not very effective since it calls grep for every (new) input line:



              target=datafile
              while IFS= read -r line ; do
              if ! grep -Fqxe "$line" "$target" ; then
              printf "%sn" "$line" >> "$target"
              fi
              done < newdata


              For each line, we use grep to see if it already exists in the target file, -F for fixed-string match (no regexes), -x for full line match, and -q to suppress output of matched lines. grep returns a falsy error code if it doesn't find a matching line, so append to target file if the negated result is truthy.




              More effectively, in awk. This relies on awk being able handle arbitrary lines as keys to an array.



              $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata 


              The first part FNR == NR lines[$0] = 1; next loads all lines of the first input file as keys into the (associative) array lines. The second part ! ($0 in lines) print runs on following input lines, and prints the line if it's not in the array, i.e. the "new" lines.



              The resulting output contains the new lines, only, so it needs to be appended to the original file, e.g. with sponge:



              $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata | sponge -a datafile


              Or we could have awk append the lines to the final line, it just requires passing the file name to awk:



              $ target=datafile 
              $ awk -vtarget="$target" 'FNR == NR lines[$0] = 1; next
              ! ($0 in lines) print >> target' "$target" newdata


              To use a here-doc with awk, we'll need to add - (stdin) as an explicit source file, in addition to setting the redirection, so awk ... "$target" - <<EOF






              share|improve this answer
























                up vote
                2
                down vote



                accepted
                +50







                up vote
                2
                down vote



                accepted
                +50




                +50




                Simple shell script to add lines from the file newdata to datafile. It should be straightforward to change newdata to a here-doc. This is really not very effective since it calls grep for every (new) input line:



                target=datafile
                while IFS= read -r line ; do
                if ! grep -Fqxe "$line" "$target" ; then
                printf "%sn" "$line" >> "$target"
                fi
                done < newdata


                For each line, we use grep to see if it already exists in the target file, -F for fixed-string match (no regexes), -x for full line match, and -q to suppress output of matched lines. grep returns a falsy error code if it doesn't find a matching line, so append to target file if the negated result is truthy.




                More effectively, in awk. This relies on awk being able handle arbitrary lines as keys to an array.



                $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata 


                The first part FNR == NR lines[$0] = 1; next loads all lines of the first input file as keys into the (associative) array lines. The second part ! ($0 in lines) print runs on following input lines, and prints the line if it's not in the array, i.e. the "new" lines.



                The resulting output contains the new lines, only, so it needs to be appended to the original file, e.g. with sponge:



                $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata | sponge -a datafile


                Or we could have awk append the lines to the final line, it just requires passing the file name to awk:



                $ target=datafile 
                $ awk -vtarget="$target" 'FNR == NR lines[$0] = 1; next
                ! ($0 in lines) print >> target' "$target" newdata


                To use a here-doc with awk, we'll need to add - (stdin) as an explicit source file, in addition to setting the redirection, so awk ... "$target" - <<EOF






                share|improve this answer














                Simple shell script to add lines from the file newdata to datafile. It should be straightforward to change newdata to a here-doc. This is really not very effective since it calls grep for every (new) input line:



                target=datafile
                while IFS= read -r line ; do
                if ! grep -Fqxe "$line" "$target" ; then
                printf "%sn" "$line" >> "$target"
                fi
                done < newdata


                For each line, we use grep to see if it already exists in the target file, -F for fixed-string match (no regexes), -x for full line match, and -q to suppress output of matched lines. grep returns a falsy error code if it doesn't find a matching line, so append to target file if the negated result is truthy.




                More effectively, in awk. This relies on awk being able handle arbitrary lines as keys to an array.



                $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata 


                The first part FNR == NR lines[$0] = 1; next loads all lines of the first input file as keys into the (associative) array lines. The second part ! ($0 in lines) print runs on following input lines, and prints the line if it's not in the array, i.e. the "new" lines.



                The resulting output contains the new lines, only, so it needs to be appended to the original file, e.g. with sponge:



                $ awk 'FNR == NR lines[$0] = 1; next ! ($0 in lines) print' datafile newdata | sponge -a datafile


                Or we could have awk append the lines to the final line, it just requires passing the file name to awk:



                $ target=datafile 
                $ awk -vtarget="$target" 'FNR == NR lines[$0] = 1; next
                ! ($0 in lines) print >> target' "$target" newdata


                To use a here-doc with awk, we'll need to add - (stdin) as an explicit source file, in addition to setting the redirection, so awk ... "$target" - <<EOF







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 17 at 18:54

























                answered Jan 17 at 14:48









                ilkkachu

                49.8k674137




                49.8k674137






















                    up vote
                    3
                    down vote













                    This solution is probably a little different than what you had in mind but I'd check whether an alias is actually defined and only add it to bashrc if it isn't. Assuming you are using a relatively current version of Bash...



                    # instead of 'alias x=y' form put them in an associative array
                    declare -A aliases
                    aliases['a']='apple'
                    aliases['ba']='banana'

                    for key in "$!aliases[@]"; do
                    if ! alias "$key" > /dev/null 2>&1; then
                    printf "alias %s='%s'n" "$key" "$aliases[$key]" >> /etc/bash.bashrc
                    fi
                    done

                    unset aliases key


                    Source this . ./scriptname rather than run it as a normal script.



                    Note: If you have a bunch of the candidate aliases and are wary of manually converting them to associative array form then you c edit the file with vim and run this commmand: :%s/valias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/.



                    OR put your candidate aliases (and nothing else) in a file (e.g. /tmp/aliases.txt) and replace the aliases[..]='..' lines in the script with this:



                    while IFS= read -r a; do 
                    eval "$a";
                    done < <(sed -E "s/alias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/" /tmp/aliases.txt)


                    Of course, there are other ways besides using AAs but they're clean and easy to work with...and I'm all in at this point. :)






                    share|improve this answer


























                      up vote
                      3
                      down vote













                      This solution is probably a little different than what you had in mind but I'd check whether an alias is actually defined and only add it to bashrc if it isn't. Assuming you are using a relatively current version of Bash...



                      # instead of 'alias x=y' form put them in an associative array
                      declare -A aliases
                      aliases['a']='apple'
                      aliases['ba']='banana'

                      for key in "$!aliases[@]"; do
                      if ! alias "$key" > /dev/null 2>&1; then
                      printf "alias %s='%s'n" "$key" "$aliases[$key]" >> /etc/bash.bashrc
                      fi
                      done

                      unset aliases key


                      Source this . ./scriptname rather than run it as a normal script.



                      Note: If you have a bunch of the candidate aliases and are wary of manually converting them to associative array form then you c edit the file with vim and run this commmand: :%s/valias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/.



                      OR put your candidate aliases (and nothing else) in a file (e.g. /tmp/aliases.txt) and replace the aliases[..]='..' lines in the script with this:



                      while IFS= read -r a; do 
                      eval "$a";
                      done < <(sed -E "s/alias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/" /tmp/aliases.txt)


                      Of course, there are other ways besides using AAs but they're clean and easy to work with...and I'm all in at this point. :)






                      share|improve this answer
























                        up vote
                        3
                        down vote










                        up vote
                        3
                        down vote









                        This solution is probably a little different than what you had in mind but I'd check whether an alias is actually defined and only add it to bashrc if it isn't. Assuming you are using a relatively current version of Bash...



                        # instead of 'alias x=y' form put them in an associative array
                        declare -A aliases
                        aliases['a']='apple'
                        aliases['ba']='banana'

                        for key in "$!aliases[@]"; do
                        if ! alias "$key" > /dev/null 2>&1; then
                        printf "alias %s='%s'n" "$key" "$aliases[$key]" >> /etc/bash.bashrc
                        fi
                        done

                        unset aliases key


                        Source this . ./scriptname rather than run it as a normal script.



                        Note: If you have a bunch of the candidate aliases and are wary of manually converting them to associative array form then you c edit the file with vim and run this commmand: :%s/valias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/.



                        OR put your candidate aliases (and nothing else) in a file (e.g. /tmp/aliases.txt) and replace the aliases[..]='..' lines in the script with this:



                        while IFS= read -r a; do 
                        eval "$a";
                        done < <(sed -E "s/alias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/" /tmp/aliases.txt)


                        Of course, there are other ways besides using AAs but they're clean and easy to work with...and I'm all in at this point. :)






                        share|improve this answer














                        This solution is probably a little different than what you had in mind but I'd check whether an alias is actually defined and only add it to bashrc if it isn't. Assuming you are using a relatively current version of Bash...



                        # instead of 'alias x=y' form put them in an associative array
                        declare -A aliases
                        aliases['a']='apple'
                        aliases['ba']='banana'

                        for key in "$!aliases[@]"; do
                        if ! alias "$key" > /dev/null 2>&1; then
                        printf "alias %s='%s'n" "$key" "$aliases[$key]" >> /etc/bash.bashrc
                        fi
                        done

                        unset aliases key


                        Source this . ./scriptname rather than run it as a normal script.



                        Note: If you have a bunch of the candidate aliases and are wary of manually converting them to associative array form then you c edit the file with vim and run this commmand: :%s/valias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/.



                        OR put your candidate aliases (and nothing else) in a file (e.g. /tmp/aliases.txt) and replace the aliases[..]='..' lines in the script with this:



                        while IFS= read -r a; do 
                        eval "$a";
                        done < <(sed -E "s/alias *([^=]+)=['"]?([^'"]+)['"]?$/aliases['1']='2'/" /tmp/aliases.txt)


                        Of course, there are other ways besides using AAs but they're clean and easy to work with...and I'm all in at this point. :)







                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Jan 13 at 13:25

























                        answered Jan 13 at 11:28









                        B Layer

                        3,8991525




                        3,8991525




















                            up vote
                            1
                            down vote













                            A generic solution for exact matches (not optimized for performance); the file input contains the lines to be checked for:



                            awk 'FNR==NR lines[NR]=$0; next; ;
                            for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; ;
                            END for(i=1;i<=length(lines);i++)
                            if (matches[i]==0) print lines[i]; ' input file


                            Testing:



                            :> cat input
                            alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                            alias brc="nano /etc/bash.bashrc"

                            :> cat file
                            a
                            b
                            c
                            alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                            d


                            Output of the awk command:



                            a
                            b
                            c
                            alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                            d
                            alias brc="nano /etc/bash.bashrc"





                            share|improve this answer
























                              up vote
                              1
                              down vote













                              A generic solution for exact matches (not optimized for performance); the file input contains the lines to be checked for:



                              awk 'FNR==NR lines[NR]=$0; next; ;
                              for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; ;
                              END for(i=1;i<=length(lines);i++)
                              if (matches[i]==0) print lines[i]; ' input file


                              Testing:



                              :> cat input
                              alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                              alias brc="nano /etc/bash.bashrc"

                              :> cat file
                              a
                              b
                              c
                              alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                              d


                              Output of the awk command:



                              a
                              b
                              c
                              alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                              d
                              alias brc="nano /etc/bash.bashrc"





                              share|improve this answer






















                                up vote
                                1
                                down vote










                                up vote
                                1
                                down vote









                                A generic solution for exact matches (not optimized for performance); the file input contains the lines to be checked for:



                                awk 'FNR==NR lines[NR]=$0; next; ;
                                for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; ;
                                END for(i=1;i<=length(lines);i++)
                                if (matches[i]==0) print lines[i]; ' input file


                                Testing:



                                :> cat input
                                alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                                alias brc="nano /etc/bash.bashrc"

                                :> cat file
                                a
                                b
                                c
                                alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                                d


                                Output of the awk command:



                                a
                                b
                                c
                                alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                                d
                                alias brc="nano /etc/bash.bashrc"





                                share|improve this answer












                                A generic solution for exact matches (not optimized for performance); the file input contains the lines to be checked for:



                                awk 'FNR==NR lines[NR]=$0; next; ;
                                for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; ;
                                END for(i=1;i<=length(lines);i++)
                                if (matches[i]==0) print lines[i]; ' input file


                                Testing:



                                :> cat input
                                alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                                alias brc="nano /etc/bash.bashrc"

                                :> cat file
                                a
                                b
                                c
                                alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                                d


                                Output of the awk command:



                                a
                                b
                                c
                                alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
                                d
                                alias brc="nano /etc/bash.bashrc"






                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered Jan 13 at 17:14









                                Hauke Laging

                                53.4k1282130




                                53.4k1282130




















                                    up vote
                                    0
                                    down vote













                                    Does the order of appended lines matter?



                                    If no, you can try such a solution:



                                    comm -1 -3 <(sort /etc/bash.bashrc) <(sort aliases) >> /etc/bash.bashrc


                                    assuming you have previously saved lines to add in the file aliases.



                                    comm is GNU coreutil (you can see the man page for it), which allows comparing two sorted files line by line.






                                    share|improve this answer
























                                      up vote
                                      0
                                      down vote













                                      Does the order of appended lines matter?



                                      If no, you can try such a solution:



                                      comm -1 -3 <(sort /etc/bash.bashrc) <(sort aliases) >> /etc/bash.bashrc


                                      assuming you have previously saved lines to add in the file aliases.



                                      comm is GNU coreutil (you can see the man page for it), which allows comparing two sorted files line by line.






                                      share|improve this answer






















                                        up vote
                                        0
                                        down vote










                                        up vote
                                        0
                                        down vote









                                        Does the order of appended lines matter?



                                        If no, you can try such a solution:



                                        comm -1 -3 <(sort /etc/bash.bashrc) <(sort aliases) >> /etc/bash.bashrc


                                        assuming you have previously saved lines to add in the file aliases.



                                        comm is GNU coreutil (you can see the man page for it), which allows comparing two sorted files line by line.






                                        share|improve this answer












                                        Does the order of appended lines matter?



                                        If no, you can try such a solution:



                                        comm -1 -3 <(sort /etc/bash.bashrc) <(sort aliases) >> /etc/bash.bashrc


                                        assuming you have previously saved lines to add in the file aliases.



                                        comm is GNU coreutil (you can see the man page for it), which allows comparing two sorted files line by line.







                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered Jan 19 at 18:47









                                        kenichi

                                        1313




                                        1313




















                                            up vote
                                            0
                                            down vote













                                            Hmmmm. How about this...



                                            Put the aliases to add in file new. Then...



                                            cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp


                                            We unique sort both the new aliases and the bashrc contents (put in a temp file to avoid race condition when we append to bashrc) and run them through comm. comm does line-by-line comparisons of sorted files and shows unique and common lines. We suppress columns 2 and 3 (-23) so the result is simply those lines that are unique to new and we append those to bashrc. That's it.



                                            (This is a totally different approach than my other answer, focusing on your quest for more of a "one-liner".)






                                            share|improve this answer


























                                              up vote
                                              0
                                              down vote













                                              Hmmmm. How about this...



                                              Put the aliases to add in file new. Then...



                                              cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp


                                              We unique sort both the new aliases and the bashrc contents (put in a temp file to avoid race condition when we append to bashrc) and run them through comm. comm does line-by-line comparisons of sorted files and shows unique and common lines. We suppress columns 2 and 3 (-23) so the result is simply those lines that are unique to new and we append those to bashrc. That's it.



                                              (This is a totally different approach than my other answer, focusing on your quest for more of a "one-liner".)






                                              share|improve this answer
























                                                up vote
                                                0
                                                down vote










                                                up vote
                                                0
                                                down vote









                                                Hmmmm. How about this...



                                                Put the aliases to add in file new. Then...



                                                cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp


                                                We unique sort both the new aliases and the bashrc contents (put in a temp file to avoid race condition when we append to bashrc) and run them through comm. comm does line-by-line comparisons of sorted files and shows unique and common lines. We suppress columns 2 and 3 (-23) so the result is simply those lines that are unique to new and we append those to bashrc. That's it.



                                                (This is a totally different approach than my other answer, focusing on your quest for more of a "one-liner".)






                                                share|improve this answer














                                                Hmmmm. How about this...



                                                Put the aliases to add in file new. Then...



                                                cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp


                                                We unique sort both the new aliases and the bashrc contents (put in a temp file to avoid race condition when we append to bashrc) and run them through comm. comm does line-by-line comparisons of sorted files and shows unique and common lines. We suppress columns 2 and 3 (-23) so the result is simply those lines that are unique to new and we append those to bashrc. That's it.



                                                (This is a totally different approach than my other answer, focusing on your quest for more of a "one-liner".)







                                                share|improve this answer














                                                share|improve this answer



                                                share|improve this answer








                                                edited Jan 20 at 10:58

























                                                answered Jan 17 at 22:50









                                                B Layer

                                                3,8991525




                                                3,8991525






















                                                     

                                                    draft saved


                                                    draft discarded


























                                                     


                                                    draft saved


                                                    draft discarded














                                                    StackExchange.ready(
                                                    function ()
                                                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f416786%2fhow-to-append-multiple-lines-to-a-file-if-these-lines-doesnt-exist-in-that-fil%23new-answer', 'question_page');

                                                    );

                                                    Post as a guest













































































                                                    Popular posts from this blog

                                                    How to check contact read email or not when send email to Individual?

                                                    Displaying single band from multi-band raster using QGIS

                                                    How many registers does an x86_64 CPU actually have?