8

I'm new to bash and would like your help; couldn't find an answer for this case. I'm trying to check if the files in one directory exist in another directory

Let's say I have the path /home/public/folder/ (here I have several files) and I want to check if the files exist in /home/private/folder2

I tried that

for file in $firstPath/*
do
   if [ -f $file ]; then
   (ask if to over write etc.. rest of the code) 

And also

for file in $firstPath/*
do
   if [ -f $file/$secondPath ]; then
   (ask if to over write etc.. rest of the code) 

Both don't work; it seems that in the first case, it compares the files in the first path (so it always ask me if I want to overwrite although it doesn't exist in the second path) And in the second case, it doesn't go inside the if statement. How could I fix that?

4
  • you got the $file and $secondPath backwards. Try if [ -f "${secondPath}/$(basename ${file}) ] Commented Dec 2, 2018 at 3:53
  • Use basename to extract the name portion of the path from $file. So something like if [ -f $secondPath/$(basename "$file") ]; then. Commented Dec 2, 2018 at 3:56
  • How to clean duplicates existing in one folder from another recursively? More generally, bash dedupe files in another directory. Commented Dec 2, 2018 at 4:40
  • How we can check *.txt files available in /home/tmp directory ?? Commented May 11, 2022 at 20:54

1 Answer 1

7

When you have a construct like for file in $firstPath/*, the value of $file is going to include the value of $firstPath, which does not exist within $secondPath. You need to strip the path in order to get the bare filename.

In traditional POSIX shell, the canonical way to do this was with an external tool called basename. You can, however, achieve what is generally thought to be equivalent functionality using Parameter Expansion, thus:

for file in "$firstPath"/*; do
   if [[ -f "$secondPath/${file##*/}" ]]; then
       # file exists, do something
   fi
done

The ${file##*/} bit is the important part here. Per the documentation linked above, this means "the $file variable, with everything up to the last / stripped out." The result should be the same as what basename produces.

As a general rule, you should quote your variables in bash. In addition, consider using [[ instead of [ unless you're actually writing POSIX shell scripts which need to be portable. You'll have a more extensive set of tests available to you, and more predictable handling of variables. There are other differences too.

Sign up to request clarification or add additional context in comments.

5 Comments

I know what you mean, but your last sentence seems to co-mingle using [[ and ... don't forget to quote your variables (within it). I know you didn't mean them together, but it may not be clear to a new reader that "[w]ord splitting and pathname expansion are not performed on the words between the [[ and ]]; ..."
@DavidC.Rankin, Good point, thanks. I've reworded, and added external references.
@ghoti How we can check *.txt files available in /home/tmp directory ??
@BhageshArora .. I'm not sure I understand what you are asking. Does it relate to this question or my answer? What do you want to check?
@ghoti For example I have file name sample_1_2_3.txt. In arguments I am getting only some of prefix not full name of file name example - sample, 1 & 2. Now How we can check sample_1_2_*.txt present in /home/tmp/ directory or not ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.