How to compare two files and if found equal ask the user to delete duplicate file by using shell script?











up vote
2
down vote

favorite












I am learning linux and was given this problem as my homework but i can't solve this that how we can compare two files content in shell mode.
(Here, we can assume that both files having text content like this
for eg.
$cat > f1
this is file 1)



$ cat duplicate_file.sh
echo "Enter file 1:"
read file1
echo "Enter file 2:"
read file2
cmp $file1 $file2 > newfile
x=` wc newfile | cut -d" " -f2 `
if [` $x -eq 0 `]
then
rm -i $file2
fi


I made this program but this ain't working!! So, Any suggestions??










share|improve this question


























    up vote
    2
    down vote

    favorite












    I am learning linux and was given this problem as my homework but i can't solve this that how we can compare two files content in shell mode.
    (Here, we can assume that both files having text content like this
    for eg.
    $cat > f1
    this is file 1)



    $ cat duplicate_file.sh
    echo "Enter file 1:"
    read file1
    echo "Enter file 2:"
    read file2
    cmp $file1 $file2 > newfile
    x=` wc newfile | cut -d" " -f2 `
    if [` $x -eq 0 `]
    then
    rm -i $file2
    fi


    I made this program but this ain't working!! So, Any suggestions??










    share|improve this question
























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I am learning linux and was given this problem as my homework but i can't solve this that how we can compare two files content in shell mode.
      (Here, we can assume that both files having text content like this
      for eg.
      $cat > f1
      this is file 1)



      $ cat duplicate_file.sh
      echo "Enter file 1:"
      read file1
      echo "Enter file 2:"
      read file2
      cmp $file1 $file2 > newfile
      x=` wc newfile | cut -d" " -f2 `
      if [` $x -eq 0 `]
      then
      rm -i $file2
      fi


      I made this program but this ain't working!! So, Any suggestions??










      share|improve this question













      I am learning linux and was given this problem as my homework but i can't solve this that how we can compare two files content in shell mode.
      (Here, we can assume that both files having text content like this
      for eg.
      $cat > f1
      this is file 1)



      $ cat duplicate_file.sh
      echo "Enter file 1:"
      read file1
      echo "Enter file 2:"
      read file2
      cmp $file1 $file2 > newfile
      x=` wc newfile | cut -d" " -f2 `
      if [` $x -eq 0 `]
      then
      rm -i $file2
      fi


      I made this program but this ain't working!! So, Any suggestions??







      shell-script files






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 10 at 6:13









      Hariom kushwaha

      111




      111






















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          4
          down vote













          The immediate issue in your code is the syntax error on the line reading



          if [` $x -eq 0 `]


          The [ and ] must be separated from the arguments within by a space character. Also, the command substitution on this line, `$x -eq 0`, is nonsensical as it would try to run the value of $x as a command.



          You also have issues with non-quoting of your variable expansions, which disqualifies your script from working on filenames containing whitespace characters and filename globbing patterns.



          The script also unconditionally clobbers the file newfile needlessly (and would fail if newfile was the name of an existing directory) and it lacks a #!-line.





          There is no point in asking the user interactively for file paths. It would be better for the user to be able to make use of the shell's filename completion on the command line and provide the pathnames to the files there as two operands:



          $ ./script.sh some/path/file1 some/other/path/file2


          If running the script in this way, the two pathnames will be available inside the script as "$1" and "$2".



          The cmp utility can be used in this script without creating a temporary file. Instead of redirecting its output, make it quiet by using its -s option (for "silent") and use its exit status to determine if the two files were identical or not.



          The script would look like



          #!/bin/sh

          if cmp -s -- "$1" "$2"; then
          rm -i -- "$2"
          fi


          Or, shorter,



          #!/bin/sh

          cmp -s -- "$1" "$2" && rm -i -- "$2"


          This would call rm -i on the second of the two given pathnames if it referred to a file with identical contents as the first pathname. The -- in the cmp and rm commands is necessary to avoid interpreting a filename starting with a dash as a set of options.



          The issue with this script, as with your own script, is that if you give it the same pathname twice, i.e. you compare a file against itself, then it will offer to remove it.



          Therefore, we also need to make sure that the two pathnames refer to two different files.



          You can do that by comparing the two pathname strings with each other:



          #!/bin/sh

          if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
          rm -i -- "$2"
          fi


          This may be enough for most applications but does not take symbolic links into account. In some shells you can also use the non-standard -ef test ("equal file") which tests whether two pathnames refer to the same file (same i-node number and device):



          #!/bin/bash

          if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
          rm -i -- "$2"
          fi


          or,



          #!/bin/bash

          ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"


          And with some sanity checks (also moving the -ef test to the sanity checks section):



          #!/bin/bash

          if [ "$#" -ne 2 ]; then
          # did not get exactly two arguments
          printf 'Usage:nt%s file1 file2n' "$0" >&2
          exit 1
          elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
          echo 'One of the files does not exist (or is not a regular file)' >&2
          exit 1
          elif [ "$1" -ef "$2" ]; then
          printf '%s and %s refer to the same filen' "$1" "$2" >&2
          exit 1
          fi

          cmp -s -- "$1" "$2" && rm -i -- "$2"


          Note that quoting the variable expansions is important since it's not uncommon for pathnames to contain spaces (on macOS, this is very common). Double quoting variable expansions also stops them from being interpreted as shell globbing patterns (your code would, for example, not work on a file called *). Also note the use of a #!-line appropriate for the script.



          If your homework assignment requires you to read the pathnames of the two files interactively, then do that with read -r and with IFS set to an empty string. This would allow you to read pathnames starting with whitespace characters and containing characters:



          #!/bin/bash

          IFS= read -p '1st pathname: ' -r p1
          IFS= read -p '2nd pathname: ' -r p2

          if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
          echo 'One of the files does not exist (or is not a regular file)' >&2
          exit 1
          elif [ "$p1" -ef "$p2" ]; then
          printf '%s and %s refer to the same filen' "$p1" "$p2" >&2
          exit 1
          fi

          cmp -s -- "$p1" "$p2" && rm -i -- "$p2"


          Related:




          • Why does my shell script choke on whitespace or other special characters?

          • Understanding "IFS= read -r line"

          • ShellCheck.net




          If you at some point need to check whether a file is empty, as in your own code, then don't call wc on it (it is inefficient as it would have to read the whole file). Instead, use a -s test:



          if [ -s "$pathname" ]; then
          printf '%s has non-zero sizen' "$pathname"
          else
          printf '%s is empty (or does not exist)n' "$pathname"
          fi


          See man test on your system, or refer to the POSIX standard for this utility.






          share|improve this answer























          • did U&L recently started offering Code Review tasks?
            – iBug
            Nov 10 at 13:50










          • @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
            – Kusalananda
            Nov 10 at 14:07




















          up vote
          3
          down vote













          First include shebang #! at the top like #!/bin/bash



          You are having two errors:



          Instead of



          cmp $file1 $file2 > newfile,


          it should be



          cmp -- "$file1" "$file2" > newfile


          as these values of these variables may have spaces, tabs, newline (characters of $IFS), *, [, ? (wildcard characters) in them or may start with -.



          Second error:



          Instead of



          if [` $x -eq 0 `]


          it should be



          if [ "$x" -eq 0 ].


          Otherwise you will get error




          bash: 0: command not found.




          Also if you are having whitespace or wildcards in the file names then it should be:



          rm -i -- "$file2" otherwise it can delete multiple files.






          share|improve this answer






























            up vote
            0
            down vote













            There are many ways to solve this, but I'll go with what you've started.



            First, don't forget the lead off the script with the interpreter string ("shebang"):



            #!/bin/bash

            echo "Enter file 1:"
            read file1
            echo "Enter file 2:"
            read file2
            cmp $file1 $file2 > newfile


            At this point you could test a couple of things:




            1. if newfile is not empty the files differ



            if [ ! -s newfile ]; then
            rm -i $file2
            fi




            1. Test the exit code for cmp operation. If it is 0, the files match.



            if [ `echo $?` == 0 ]; then
            rm -i $file2
            fi



            Also, your wc command isn't quite working. Try running it outside of the script. Do you get the result you're expecting?






            share|improve this answer





















            • I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
              – Debian_yadav
              Nov 10 at 7:48






            • 1




              Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
              – Kusalananda
              Nov 10 at 9:49











            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',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            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%2f480903%2fhow-to-compare-two-files-and-if-found-equal-ask-the-user-to-delete-duplicate-fil%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            3 Answers
            3






            active

            oldest

            votes








            3 Answers
            3






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            4
            down vote













            The immediate issue in your code is the syntax error on the line reading



            if [` $x -eq 0 `]


            The [ and ] must be separated from the arguments within by a space character. Also, the command substitution on this line, `$x -eq 0`, is nonsensical as it would try to run the value of $x as a command.



            You also have issues with non-quoting of your variable expansions, which disqualifies your script from working on filenames containing whitespace characters and filename globbing patterns.



            The script also unconditionally clobbers the file newfile needlessly (and would fail if newfile was the name of an existing directory) and it lacks a #!-line.





            There is no point in asking the user interactively for file paths. It would be better for the user to be able to make use of the shell's filename completion on the command line and provide the pathnames to the files there as two operands:



            $ ./script.sh some/path/file1 some/other/path/file2


            If running the script in this way, the two pathnames will be available inside the script as "$1" and "$2".



            The cmp utility can be used in this script without creating a temporary file. Instead of redirecting its output, make it quiet by using its -s option (for "silent") and use its exit status to determine if the two files were identical or not.



            The script would look like



            #!/bin/sh

            if cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            Or, shorter,



            #!/bin/sh

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            This would call rm -i on the second of the two given pathnames if it referred to a file with identical contents as the first pathname. The -- in the cmp and rm commands is necessary to avoid interpreting a filename starting with a dash as a set of options.



            The issue with this script, as with your own script, is that if you give it the same pathname twice, i.e. you compare a file against itself, then it will offer to remove it.



            Therefore, we also need to make sure that the two pathnames refer to two different files.



            You can do that by comparing the two pathname strings with each other:



            #!/bin/sh

            if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            This may be enough for most applications but does not take symbolic links into account. In some shells you can also use the non-standard -ef test ("equal file") which tests whether two pathnames refer to the same file (same i-node number and device):



            #!/bin/bash

            if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            or,



            #!/bin/bash

            ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"


            And with some sanity checks (also moving the -ef test to the sanity checks section):



            #!/bin/bash

            if [ "$#" -ne 2 ]; then
            # did not get exactly two arguments
            printf 'Usage:nt%s file1 file2n' "$0" >&2
            exit 1
            elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$1" -ef "$2" ]; then
            printf '%s and %s refer to the same filen' "$1" "$2" >&2
            exit 1
            fi

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            Note that quoting the variable expansions is important since it's not uncommon for pathnames to contain spaces (on macOS, this is very common). Double quoting variable expansions also stops them from being interpreted as shell globbing patterns (your code would, for example, not work on a file called *). Also note the use of a #!-line appropriate for the script.



            If your homework assignment requires you to read the pathnames of the two files interactively, then do that with read -r and with IFS set to an empty string. This would allow you to read pathnames starting with whitespace characters and containing characters:



            #!/bin/bash

            IFS= read -p '1st pathname: ' -r p1
            IFS= read -p '2nd pathname: ' -r p2

            if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$p1" -ef "$p2" ]; then
            printf '%s and %s refer to the same filen' "$p1" "$p2" >&2
            exit 1
            fi

            cmp -s -- "$p1" "$p2" && rm -i -- "$p2"


            Related:




            • Why does my shell script choke on whitespace or other special characters?

            • Understanding "IFS= read -r line"

            • ShellCheck.net




            If you at some point need to check whether a file is empty, as in your own code, then don't call wc on it (it is inefficient as it would have to read the whole file). Instead, use a -s test:



            if [ -s "$pathname" ]; then
            printf '%s has non-zero sizen' "$pathname"
            else
            printf '%s is empty (or does not exist)n' "$pathname"
            fi


            See man test on your system, or refer to the POSIX standard for this utility.






            share|improve this answer























            • did U&L recently started offering Code Review tasks?
              – iBug
              Nov 10 at 13:50










            • @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
              – Kusalananda
              Nov 10 at 14:07

















            up vote
            4
            down vote













            The immediate issue in your code is the syntax error on the line reading



            if [` $x -eq 0 `]


            The [ and ] must be separated from the arguments within by a space character. Also, the command substitution on this line, `$x -eq 0`, is nonsensical as it would try to run the value of $x as a command.



            You also have issues with non-quoting of your variable expansions, which disqualifies your script from working on filenames containing whitespace characters and filename globbing patterns.



            The script also unconditionally clobbers the file newfile needlessly (and would fail if newfile was the name of an existing directory) and it lacks a #!-line.





            There is no point in asking the user interactively for file paths. It would be better for the user to be able to make use of the shell's filename completion on the command line and provide the pathnames to the files there as two operands:



            $ ./script.sh some/path/file1 some/other/path/file2


            If running the script in this way, the two pathnames will be available inside the script as "$1" and "$2".



            The cmp utility can be used in this script without creating a temporary file. Instead of redirecting its output, make it quiet by using its -s option (for "silent") and use its exit status to determine if the two files were identical or not.



            The script would look like



            #!/bin/sh

            if cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            Or, shorter,



            #!/bin/sh

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            This would call rm -i on the second of the two given pathnames if it referred to a file with identical contents as the first pathname. The -- in the cmp and rm commands is necessary to avoid interpreting a filename starting with a dash as a set of options.



            The issue with this script, as with your own script, is that if you give it the same pathname twice, i.e. you compare a file against itself, then it will offer to remove it.



            Therefore, we also need to make sure that the two pathnames refer to two different files.



            You can do that by comparing the two pathname strings with each other:



            #!/bin/sh

            if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            This may be enough for most applications but does not take symbolic links into account. In some shells you can also use the non-standard -ef test ("equal file") which tests whether two pathnames refer to the same file (same i-node number and device):



            #!/bin/bash

            if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            or,



            #!/bin/bash

            ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"


            And with some sanity checks (also moving the -ef test to the sanity checks section):



            #!/bin/bash

            if [ "$#" -ne 2 ]; then
            # did not get exactly two arguments
            printf 'Usage:nt%s file1 file2n' "$0" >&2
            exit 1
            elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$1" -ef "$2" ]; then
            printf '%s and %s refer to the same filen' "$1" "$2" >&2
            exit 1
            fi

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            Note that quoting the variable expansions is important since it's not uncommon for pathnames to contain spaces (on macOS, this is very common). Double quoting variable expansions also stops them from being interpreted as shell globbing patterns (your code would, for example, not work on a file called *). Also note the use of a #!-line appropriate for the script.



            If your homework assignment requires you to read the pathnames of the two files interactively, then do that with read -r and with IFS set to an empty string. This would allow you to read pathnames starting with whitespace characters and containing characters:



            #!/bin/bash

            IFS= read -p '1st pathname: ' -r p1
            IFS= read -p '2nd pathname: ' -r p2

            if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$p1" -ef "$p2" ]; then
            printf '%s and %s refer to the same filen' "$p1" "$p2" >&2
            exit 1
            fi

            cmp -s -- "$p1" "$p2" && rm -i -- "$p2"


            Related:




            • Why does my shell script choke on whitespace or other special characters?

            • Understanding "IFS= read -r line"

            • ShellCheck.net




            If you at some point need to check whether a file is empty, as in your own code, then don't call wc on it (it is inefficient as it would have to read the whole file). Instead, use a -s test:



            if [ -s "$pathname" ]; then
            printf '%s has non-zero sizen' "$pathname"
            else
            printf '%s is empty (or does not exist)n' "$pathname"
            fi


            See man test on your system, or refer to the POSIX standard for this utility.






            share|improve this answer























            • did U&L recently started offering Code Review tasks?
              – iBug
              Nov 10 at 13:50










            • @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
              – Kusalananda
              Nov 10 at 14:07















            up vote
            4
            down vote










            up vote
            4
            down vote









            The immediate issue in your code is the syntax error on the line reading



            if [` $x -eq 0 `]


            The [ and ] must be separated from the arguments within by a space character. Also, the command substitution on this line, `$x -eq 0`, is nonsensical as it would try to run the value of $x as a command.



            You also have issues with non-quoting of your variable expansions, which disqualifies your script from working on filenames containing whitespace characters and filename globbing patterns.



            The script also unconditionally clobbers the file newfile needlessly (and would fail if newfile was the name of an existing directory) and it lacks a #!-line.





            There is no point in asking the user interactively for file paths. It would be better for the user to be able to make use of the shell's filename completion on the command line and provide the pathnames to the files there as two operands:



            $ ./script.sh some/path/file1 some/other/path/file2


            If running the script in this way, the two pathnames will be available inside the script as "$1" and "$2".



            The cmp utility can be used in this script without creating a temporary file. Instead of redirecting its output, make it quiet by using its -s option (for "silent") and use its exit status to determine if the two files were identical or not.



            The script would look like



            #!/bin/sh

            if cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            Or, shorter,



            #!/bin/sh

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            This would call rm -i on the second of the two given pathnames if it referred to a file with identical contents as the first pathname. The -- in the cmp and rm commands is necessary to avoid interpreting a filename starting with a dash as a set of options.



            The issue with this script, as with your own script, is that if you give it the same pathname twice, i.e. you compare a file against itself, then it will offer to remove it.



            Therefore, we also need to make sure that the two pathnames refer to two different files.



            You can do that by comparing the two pathname strings with each other:



            #!/bin/sh

            if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            This may be enough for most applications but does not take symbolic links into account. In some shells you can also use the non-standard -ef test ("equal file") which tests whether two pathnames refer to the same file (same i-node number and device):



            #!/bin/bash

            if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            or,



            #!/bin/bash

            ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"


            And with some sanity checks (also moving the -ef test to the sanity checks section):



            #!/bin/bash

            if [ "$#" -ne 2 ]; then
            # did not get exactly two arguments
            printf 'Usage:nt%s file1 file2n' "$0" >&2
            exit 1
            elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$1" -ef "$2" ]; then
            printf '%s and %s refer to the same filen' "$1" "$2" >&2
            exit 1
            fi

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            Note that quoting the variable expansions is important since it's not uncommon for pathnames to contain spaces (on macOS, this is very common). Double quoting variable expansions also stops them from being interpreted as shell globbing patterns (your code would, for example, not work on a file called *). Also note the use of a #!-line appropriate for the script.



            If your homework assignment requires you to read the pathnames of the two files interactively, then do that with read -r and with IFS set to an empty string. This would allow you to read pathnames starting with whitespace characters and containing characters:



            #!/bin/bash

            IFS= read -p '1st pathname: ' -r p1
            IFS= read -p '2nd pathname: ' -r p2

            if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$p1" -ef "$p2" ]; then
            printf '%s and %s refer to the same filen' "$p1" "$p2" >&2
            exit 1
            fi

            cmp -s -- "$p1" "$p2" && rm -i -- "$p2"


            Related:




            • Why does my shell script choke on whitespace or other special characters?

            • Understanding "IFS= read -r line"

            • ShellCheck.net




            If you at some point need to check whether a file is empty, as in your own code, then don't call wc on it (it is inefficient as it would have to read the whole file). Instead, use a -s test:



            if [ -s "$pathname" ]; then
            printf '%s has non-zero sizen' "$pathname"
            else
            printf '%s is empty (or does not exist)n' "$pathname"
            fi


            See man test on your system, or refer to the POSIX standard for this utility.






            share|improve this answer














            The immediate issue in your code is the syntax error on the line reading



            if [` $x -eq 0 `]


            The [ and ] must be separated from the arguments within by a space character. Also, the command substitution on this line, `$x -eq 0`, is nonsensical as it would try to run the value of $x as a command.



            You also have issues with non-quoting of your variable expansions, which disqualifies your script from working on filenames containing whitespace characters and filename globbing patterns.



            The script also unconditionally clobbers the file newfile needlessly (and would fail if newfile was the name of an existing directory) and it lacks a #!-line.





            There is no point in asking the user interactively for file paths. It would be better for the user to be able to make use of the shell's filename completion on the command line and provide the pathnames to the files there as two operands:



            $ ./script.sh some/path/file1 some/other/path/file2


            If running the script in this way, the two pathnames will be available inside the script as "$1" and "$2".



            The cmp utility can be used in this script without creating a temporary file. Instead of redirecting its output, make it quiet by using its -s option (for "silent") and use its exit status to determine if the two files were identical or not.



            The script would look like



            #!/bin/sh

            if cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            Or, shorter,



            #!/bin/sh

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            This would call rm -i on the second of the two given pathnames if it referred to a file with identical contents as the first pathname. The -- in the cmp and rm commands is necessary to avoid interpreting a filename starting with a dash as a set of options.



            The issue with this script, as with your own script, is that if you give it the same pathname twice, i.e. you compare a file against itself, then it will offer to remove it.



            Therefore, we also need to make sure that the two pathnames refer to two different files.



            You can do that by comparing the two pathname strings with each other:



            #!/bin/sh

            if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            This may be enough for most applications but does not take symbolic links into account. In some shells you can also use the non-standard -ef test ("equal file") which tests whether two pathnames refer to the same file (same i-node number and device):



            #!/bin/bash

            if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
            rm -i -- "$2"
            fi


            or,



            #!/bin/bash

            ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"


            And with some sanity checks (also moving the -ef test to the sanity checks section):



            #!/bin/bash

            if [ "$#" -ne 2 ]; then
            # did not get exactly two arguments
            printf 'Usage:nt%s file1 file2n' "$0" >&2
            exit 1
            elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$1" -ef "$2" ]; then
            printf '%s and %s refer to the same filen' "$1" "$2" >&2
            exit 1
            fi

            cmp -s -- "$1" "$2" && rm -i -- "$2"


            Note that quoting the variable expansions is important since it's not uncommon for pathnames to contain spaces (on macOS, this is very common). Double quoting variable expansions also stops them from being interpreted as shell globbing patterns (your code would, for example, not work on a file called *). Also note the use of a #!-line appropriate for the script.



            If your homework assignment requires you to read the pathnames of the two files interactively, then do that with read -r and with IFS set to an empty string. This would allow you to read pathnames starting with whitespace characters and containing characters:



            #!/bin/bash

            IFS= read -p '1st pathname: ' -r p1
            IFS= read -p '2nd pathname: ' -r p2

            if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
            echo 'One of the files does not exist (or is not a regular file)' >&2
            exit 1
            elif [ "$p1" -ef "$p2" ]; then
            printf '%s and %s refer to the same filen' "$p1" "$p2" >&2
            exit 1
            fi

            cmp -s -- "$p1" "$p2" && rm -i -- "$p2"


            Related:




            • Why does my shell script choke on whitespace or other special characters?

            • Understanding "IFS= read -r line"

            • ShellCheck.net




            If you at some point need to check whether a file is empty, as in your own code, then don't call wc on it (it is inefficient as it would have to read the whole file). Instead, use a -s test:



            if [ -s "$pathname" ]; then
            printf '%s has non-zero sizen' "$pathname"
            else
            printf '%s is empty (or does not exist)n' "$pathname"
            fi


            See man test on your system, or refer to the POSIX standard for this utility.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 10 at 14:09

























            answered Nov 10 at 11:49









            Kusalananda

            121k16226370




            121k16226370












            • did U&L recently started offering Code Review tasks?
              – iBug
              Nov 10 at 13:50










            • @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
              – Kusalananda
              Nov 10 at 14:07




















            • did U&L recently started offering Code Review tasks?
              – iBug
              Nov 10 at 13:50










            • @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
              – Kusalananda
              Nov 10 at 14:07


















            did U&L recently started offering Code Review tasks?
            – iBug
            Nov 10 at 13:50




            did U&L recently started offering Code Review tasks?
            – iBug
            Nov 10 at 13:50












            @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
            – Kusalananda
            Nov 10 at 14:07






            @iBug Not really. To be able to help someone with coding issues, one would need to see the code. Then, it's a matter of picking it apart and suggesting better alternatives. I don't see any other way to do it. If you call it code review, then maybe it is a code review. I'm calling it answering a question.
            – Kusalananda
            Nov 10 at 14:07














            up vote
            3
            down vote













            First include shebang #! at the top like #!/bin/bash



            You are having two errors:



            Instead of



            cmp $file1 $file2 > newfile,


            it should be



            cmp -- "$file1" "$file2" > newfile


            as these values of these variables may have spaces, tabs, newline (characters of $IFS), *, [, ? (wildcard characters) in them or may start with -.



            Second error:



            Instead of



            if [` $x -eq 0 `]


            it should be



            if [ "$x" -eq 0 ].


            Otherwise you will get error




            bash: 0: command not found.




            Also if you are having whitespace or wildcards in the file names then it should be:



            rm -i -- "$file2" otherwise it can delete multiple files.






            share|improve this answer



























              up vote
              3
              down vote













              First include shebang #! at the top like #!/bin/bash



              You are having two errors:



              Instead of



              cmp $file1 $file2 > newfile,


              it should be



              cmp -- "$file1" "$file2" > newfile


              as these values of these variables may have spaces, tabs, newline (characters of $IFS), *, [, ? (wildcard characters) in them or may start with -.



              Second error:



              Instead of



              if [` $x -eq 0 `]


              it should be



              if [ "$x" -eq 0 ].


              Otherwise you will get error




              bash: 0: command not found.




              Also if you are having whitespace or wildcards in the file names then it should be:



              rm -i -- "$file2" otherwise it can delete multiple files.






              share|improve this answer

























                up vote
                3
                down vote










                up vote
                3
                down vote









                First include shebang #! at the top like #!/bin/bash



                You are having two errors:



                Instead of



                cmp $file1 $file2 > newfile,


                it should be



                cmp -- "$file1" "$file2" > newfile


                as these values of these variables may have spaces, tabs, newline (characters of $IFS), *, [, ? (wildcard characters) in them or may start with -.



                Second error:



                Instead of



                if [` $x -eq 0 `]


                it should be



                if [ "$x" -eq 0 ].


                Otherwise you will get error




                bash: 0: command not found.




                Also if you are having whitespace or wildcards in the file names then it should be:



                rm -i -- "$file2" otherwise it can delete multiple files.






                share|improve this answer














                First include shebang #! at the top like #!/bin/bash



                You are having two errors:



                Instead of



                cmp $file1 $file2 > newfile,


                it should be



                cmp -- "$file1" "$file2" > newfile


                as these values of these variables may have spaces, tabs, newline (characters of $IFS), *, [, ? (wildcard characters) in them or may start with -.



                Second error:



                Instead of



                if [` $x -eq 0 `]


                it should be



                if [ "$x" -eq 0 ].


                Otherwise you will get error




                bash: 0: command not found.




                Also if you are having whitespace or wildcards in the file names then it should be:



                rm -i -- "$file2" otherwise it can delete multiple files.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 10 at 8:19









                Stéphane Chazelas

                298k54563910




                298k54563910










                answered Nov 10 at 7:40









                Debian_yadav

                1,3653922




                1,3653922






















                    up vote
                    0
                    down vote













                    There are many ways to solve this, but I'll go with what you've started.



                    First, don't forget the lead off the script with the interpreter string ("shebang"):



                    #!/bin/bash

                    echo "Enter file 1:"
                    read file1
                    echo "Enter file 2:"
                    read file2
                    cmp $file1 $file2 > newfile


                    At this point you could test a couple of things:




                    1. if newfile is not empty the files differ



                    if [ ! -s newfile ]; then
                    rm -i $file2
                    fi




                    1. Test the exit code for cmp operation. If it is 0, the files match.



                    if [ `echo $?` == 0 ]; then
                    rm -i $file2
                    fi



                    Also, your wc command isn't quite working. Try running it outside of the script. Do you get the result you're expecting?






                    share|improve this answer





















                    • I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
                      – Debian_yadav
                      Nov 10 at 7:48






                    • 1




                      Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
                      – Kusalananda
                      Nov 10 at 9:49















                    up vote
                    0
                    down vote













                    There are many ways to solve this, but I'll go with what you've started.



                    First, don't forget the lead off the script with the interpreter string ("shebang"):



                    #!/bin/bash

                    echo "Enter file 1:"
                    read file1
                    echo "Enter file 2:"
                    read file2
                    cmp $file1 $file2 > newfile


                    At this point you could test a couple of things:




                    1. if newfile is not empty the files differ



                    if [ ! -s newfile ]; then
                    rm -i $file2
                    fi




                    1. Test the exit code for cmp operation. If it is 0, the files match.



                    if [ `echo $?` == 0 ]; then
                    rm -i $file2
                    fi



                    Also, your wc command isn't quite working. Try running it outside of the script. Do you get the result you're expecting?






                    share|improve this answer





















                    • I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
                      – Debian_yadav
                      Nov 10 at 7:48






                    • 1




                      Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
                      – Kusalananda
                      Nov 10 at 9:49













                    up vote
                    0
                    down vote










                    up vote
                    0
                    down vote









                    There are many ways to solve this, but I'll go with what you've started.



                    First, don't forget the lead off the script with the interpreter string ("shebang"):



                    #!/bin/bash

                    echo "Enter file 1:"
                    read file1
                    echo "Enter file 2:"
                    read file2
                    cmp $file1 $file2 > newfile


                    At this point you could test a couple of things:




                    1. if newfile is not empty the files differ



                    if [ ! -s newfile ]; then
                    rm -i $file2
                    fi




                    1. Test the exit code for cmp operation. If it is 0, the files match.



                    if [ `echo $?` == 0 ]; then
                    rm -i $file2
                    fi



                    Also, your wc command isn't quite working. Try running it outside of the script. Do you get the result you're expecting?






                    share|improve this answer












                    There are many ways to solve this, but I'll go with what you've started.



                    First, don't forget the lead off the script with the interpreter string ("shebang"):



                    #!/bin/bash

                    echo "Enter file 1:"
                    read file1
                    echo "Enter file 2:"
                    read file2
                    cmp $file1 $file2 > newfile


                    At this point you could test a couple of things:




                    1. if newfile is not empty the files differ



                    if [ ! -s newfile ]; then
                    rm -i $file2
                    fi




                    1. Test the exit code for cmp operation. If it is 0, the files match.



                    if [ `echo $?` == 0 ]; then
                    rm -i $file2
                    fi



                    Also, your wc command isn't quite working. Try running it outside of the script. Do you get the result you're expecting?







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 10 at 7:32









                    kevlinux

                    1642




                    1642












                    • I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
                      – Debian_yadav
                      Nov 10 at 7:48






                    • 1




                      Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
                      – Kusalananda
                      Nov 10 at 9:49


















                    • I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
                      – Debian_yadav
                      Nov 10 at 7:48






                    • 1




                      Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
                      – Kusalananda
                      Nov 10 at 9:49
















                    I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
                    – Debian_yadav
                    Nov 10 at 7:48




                    I think wc command is working, when I tested it, the problem is in cmp $file1 $file2 > newfile command.
                    – Debian_yadav
                    Nov 10 at 7:48




                    1




                    1




                    Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
                    – Kusalananda
                    Nov 10 at 9:49




                    Why not test with if cmp -s -- "$file1" "$file2"; then? No point in the temporary file really...
                    – Kusalananda
                    Nov 10 at 9:49


















                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Unix & Linux Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f480903%2fhow-to-compare-two-files-and-if-found-equal-ask-the-user-to-delete-duplicate-fil%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    這個網誌中的熱門文章

                    Tangent Lines Diagram Along Smooth Curve

                    Yusuf al-Mu'taman ibn Hud

                    Zucchini