1

I have a requirement in a shell script. I get this location information from a text file; it is always valid.

/opt/sasuapps/senny/publish/gbl/SANDHYA/drop1

I need to check if the directory is empty or not which I have done. If the directory is not empty, I need to delete the files and directory under that location.

As a part of security check, I would like to check if the drop location got from the file (/opt/sasuapps/senny/publish/gbl/SANDHYA/drop1) starts with any of the below.

/mnt/senny_publish/gbl
/mnt/senny/publish/gbl
/opt/sasuapps/senny/publish/gbl

If yes then only go ahead and delete; else don't do anything.

How can I compare the location given with those fixed strings?

1
  • But what's your problem? You wrote what you want, but you didn't write what you can't do.. Besides 'shell' can mean really many languages so what are you really interested in ? Commented Nov 10, 2009 at 4:20

4 Answers 4

3

This will work in bash and any other Posix-style shell, i.e., it's OK for systems where /bin/sh is not bash.

check () {
  [ "x$1" = x ] && return 1
  for pf in /mnt/senny_publish/gbl              \
            /mnt/senny/publish/gbl              \
            /opt/sasuapps/senny/publish/gbl; do
      suf="${1#$pf}"
      [ x"$pf$suf" = x"$1" ] && return 0
  done
  return 1
}

testcheck () {
  echo -n "$1" :
  if check "$1"; then
      echo OK
  else
      echo BAD
  fi
}

testcheck /how/now
testcheck /not/this
testcheck /mnt/senny_publish/gbl
testcheck /mnt/senny/publish/gbl
testcheck /opt/sasuapps/senny/publish/gbl
testcheck /mnt/senny_publish/gbl/a/b
testcheck /mnt/senny/publish/gbl/a/b
testcheck /opt/sasuapps/senny/publish/gbl/a/b

So...

/how/now :BAD
/not/this :BAD
/mnt/senny_publish/gbl :OK
/mnt/senny/publish/gbl :OK
/opt/sasuapps/senny/publish/gbl :OK
/mnt/senny_publish/gbl/a/b :OK
/mnt/senny/publish/gbl/a/b :OK
/opt/sasuapps/senny/publish/gbl/a/b :OK

By avoiding grep and other external programs, we keep execution entirely in the shell, avoiding fork's and exec's, and which may also give additional protection against XSS attacks. Still, it would be a good idea to filter metachars early.

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

1 Comment

You forgot the output of your testcheck runs.
2

Assuming you are using bash for your shell script:

if [ -n "$(echo $LOCATION|grep -lE '/mnt/senny_publish/gbl|/mnt/senny/publish/gbl|/opt/sasuapps/senny/publish/gbl')" ]
then
    # Contains one of these paths
else
    # Does not contain one of these paths
fi

If you have a longer list of paths to look through, you could dump them to a tempfile, one per line, and use grep -lEf tempFileWithPaths.txt

4 Comments

You probably also want to pass the -q option to grep to avoid printing extraneous junk to stdout
Technically, you've not enforced the 'starts with' condition; fixing that requires '^(...as before)'.
@Adam: he requires the output from -l to make the value non-empty. The standard output is captured and not echoed to the world.
@Jonathan: D'oh, you're right, I didn't read it very carefully.
2

Using case is a lot cleaner:

case $d in
/mnt/foo/gbl/*|/mnt/bar/publish/gbl/*|/opt/sasu/bar/publish/gbl/*)
    rm -fr "$d"
esac

..for everyday use. This is POSIX-compliant and quick.

If you want to make it into a function, you could do:

# prefixed_by "$locn" "$safe_pfx" '/dir/list'
prefixed_by() {
    [ -n "$1" ] || return
    local i f=$1; shift
    for i; do
        i=${i%/}
        case $f in
        "$i/"*) return 0
        esac
    done
    return 1
}

So, if you know the list never has spaces or wildcard characters in it (ie: it's set directly in your script with a string literal) you could do:

readonly safe_list='/mnt/foo/gbl /mnt/bar/publish/gbl /opt/sasu/bar/publish/gbl'

..in initialisation, and then later:

prefixed_by "$d" $safe_list && rm -fr "$d"

I've used local in the function, which isn't specified in POSIX, though most modern shells have it: you can change that to fit your circumstance, as the rest is all POSIX-compliant.

In BASH, you don't have to use case in the for loop: you can just use [[ which pattern-matches, ie:

[[ $f = "$i"/* ]] && return

It also doesn't word-split nor perform any filename expansion. Quoting the "$i" is needed, however to ensure any wildcard characters like * or ? are not used as wildcards.

Comments

0

use sed command

Comments

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.