2009-11-10 81 views
0

我在shell脚本中有一个需求。我从文本文件中获取此位置信息;它总是有效的。如何测试一个字符串是否以一个外壳前缀列表中的前缀开头

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

我需要检查目录是否为空或者我没有做过。如果该目录不是空的,我需要删除该位置下的文件和目录。

作为安全检查的一部分,我想检查是否放置位置从文件中得到了(/选择/ sasuapps/senny /出版/ GBL /桑德亚/ drop1)与任何下方开始。

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

如果是,那么只能继续并删除;否则不要做任何事情。

我怎样才能比较给定的位置和那些固定的字符串?

+0

但是你的问题是什么?你写了你想要的东西,但是你没有写出你不能做的事情。除了'shell'可能意味着很多语言,所以你真正感兴趣的是什么? – kubal5003 2009-11-10 04:20:00

回答

2

假设你正在使用bash为你的shell脚本:

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

+1

您可能还希望将'-q'选项传递给grep以避免将多余的垃圾打印到标准输出 – 2009-11-10 04:28:24

+2

从技术上讲,您没有强制执行'starts with'条件;修复需要'^(...和以前一样)'。 – 2009-11-10 04:29:17

+1

@Adam:他要求-l的输出使值非空。标准输出被捕获并且没有回应到世界。 – 2009-11-10 04:30:08

0

使用sed的命令

3

这将在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攻击额外的保护。尽管如此,早期过滤metachars是一个好主意。

+0

您忘记了testcheck运行的输出。 – 2009-11-10 05:58:40

2

使用case是有很多清洁:

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

..for日常使用。这是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' 

..in初始化,再后来:

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

我在函数中使用了local,虽然大多数现代shell都有它,但在POSIX中没有指定它:您可以根据自己的情况更改它,因为其余的都符合POSIX标准。

在bash,你不必在for循环使用case:你可以使用的图案匹配[[,即:

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

它也不会字分割,也不进行任何文件名扩展。需要引用"$i",但要确保不使用*?之类的通配符作为通配符。

相关问题