I am searching for one file, say "file1.txt", and output of find command is like below.
/home/nicool/Desktop/file1.txt
/home/nicool/Desktop/dir1/file1.txt
/home/nicool/Desktop/dir1/dir2/file1.txt
In above cases I want only common parent directory, which is "/home/nicool/Desktop" in above case. How it can be achieved using bash? Please help to find general solution for such problem.
This script reads lines and stores the common prefix in each iteration:
# read a line into the variable "prefix", split at slashes
IFS=/ read -a prefix
# while there are more lines, one after another read them into "next",
# also split at slashes
while IFS=/ read -a next; do
    new_prefix=()
    # for all indexes in prefix
    for ((i=0; i < "${#prefix[@]}"; ++i)); do
        # if the word in the new line matches the old one
        if [[ "${prefix[i]}" == "${next[i]}" ]]; then
            # then append to the new prefix
            new_prefix+=("${prefix[i]}")
        else
            # otherwise break out of the loop
            break
        fi
    done
    prefix=("${new_prefix[@]}")
done
# join an array
function join {
    # copied from: http://stackoverflow.com/a/17841619/416224
    local IFS="$1"
    shift
    echo "$*"
}
# join the common prefix array using slashes
join / "${prefix[@]}"
Example:
$ ./x.sh <<eof
/home/nicool/Desktop1/file1.txt
/home/nicool/Desktop2/dir1/file1.txt
/home/nicool/Desktop3/dir1/dir2/file1.txt
eof
/home/nicool
                        I don't think there's a bash builtin for this, but you can use this script, and pipe your find into it.
read -r FIRSTLINE
DIR=$(dirname "$FIRSTLINE")
while read -r NEXTLINE; do
  until [[ "${NEXTLINE:0:${#DIR}}" = "$DIR" || "$DIR" = "/" ]]; do
    DIR=$(dirname "$DIR")
  done
done
echo $DIR
For added safety, use -print0 on your find, and adjust your read statements to have -d '\0'. This will work with filenames that have newlines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With