Как проверить, начинается ли строка с префикса из списка префиксов в оболочке - PullRequest
0 голосов
/ 10 ноября 2009

У меня есть требование в сценарии оболочки. Я получаю эту информацию о местоположении из текстового файла; это всегда верно.

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

Мне нужно проверить, пустой каталог или нет, что я и сделал. Если каталог не пустой, мне нужно удалить файлы и каталог в этом месте.

Как часть проверки безопасности, я хотел бы проверить, начинается ли место для удаления, полученное из файла (/ opt / sasuapps / senny / publish / gbl / SANDHYA / drop1), любым из нижеперечисленных.

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

Если да, тогда только удалите; иначе ничего не делай.

Как я могу сравнить местоположение, указанное с этими фиксированными строками?

Ответы [ 4 ]

3 голосов
/ 10 ноября 2009

Это будет работать в bash и любой другой оболочке в стиле Posix, т.е. это нормально для систем, где / bin / sh не 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

Итак ...

/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

Избегая grep и других внешних программ, мы полностью сохраняем выполнение в оболочке, избегая форка и exec, что также может дать дополнительную защиту от XSS-атак. Тем не менее, было бы неплохо отфильтровать метачары как можно раньше.

2 голосов
/ 25 июня 2012

Использование case намного чище:

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

.. для повседневного использования. Это POSIX-совместимый и быстрый.

Если вы хотите превратить это в функцию, вы можете сделать:

# 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
}

Итак, если вы знаете , в списке никогда нет пробелов или подстановочных знаков (т. Е. Он установлен прямо в вашем скрипте со строковым литералом), вы можете сделать:

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

.. при инициализации, а затем позже:

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

Я использовал local в функции, которая не указана в POSIX, хотя в большинстве современных оболочек она есть: вы можете изменить это в соответствии с вашими обстоятельствами, так как остальное полностью соответствует POSIX.

В BASH вам не нужно использовать case в цикле for: вы можете просто использовать [[, какой шаблон соответствует, то есть:

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

Он также не разделяет слова и не выполняет расширение имени файла. Кавычки "$i" необходимы, однако, чтобы любые символы подстановки, такие как * или ?, не использовались как символы подстановки.

2 голосов
/ 10 ноября 2009

Если вы используете bash для своего сценария оболочки:

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

Если у вас есть более длинный список путей для просмотра, вы можете сбросить их в временный файл, по одному на строку, и использовать grep -lEf tempFileWithPaths.txt

0 голосов
/ 10 ноября 2009

использование sed команда

...