bashcmp

How to cmp multiple files with relative paths using bash


I have a directory called filesystem that looks a little like this:

- filesystem
  - etc
    - systemd
      - system
        - custom.service
        - custom2.service
  - hostname

These files are copied into the root directory then need to be verified. For example: filesystem/etc/hostname is copied into /etc/hostname.

I've tried this to write a bash script to compare every file in filesystem.

for file in $(find filesystem -type f)
do
  cmp file ${file#filesystem}
done

The purpose of ${file#filesystem} is to remove the 'filesystem' from the path of the second file.

This isn't working - it returns 'No such file or directory'. How to fix this code?


Solution

  • As noted in the comments, the specific problem with your code is that you were missing a $ to expand file. That said, processing the output of ls or find can run into problems whenever filenames contain any IFS character. Spaces are a common example, but newlines will trip up many attempts to handle the spaces.

    One option for addressing this is to use -exec with find and invoking a shell, since you need some of the shell capabilities for parameter expansion.

    Here we'll use sh -c with a string to run which is the cmp command, and we'll pass that sh 2 arguments the first being a placeholder that's the shell's name, the second being the filename parameter:

    find filesystem -type f -exec sh -c 'cmp "$1" "${1#filesystem}"' _ {} \;
    

    We quote the variables within sh -c and find will ensure {} is passed in correctly as a single argument.