我有一个Bash脚本,它接受一个目录作为参数,经过一些处理后会根据该目录中的文件做一些输出。
该命令如下所示,其中dir
是
dir/foo
dir/bob
dir/haha
dir/bar
dir/sub-dir
dir/sub-dir/joe
> myscript ~/files/stuff/dir
经过一些处理后,我希望输出就像这样
foo
bar
sub-dir/joe
我必须删除传入路径的代码如下:
shopt -s extglob
for file in $files ; do
filename=${file#${1}?(/)}
这让我得到以下内容,但由于某种原因,可选/
未被处理。因此,我的输出如下所示:
/foo
/bar
/sub-dir/joe
我将其设为可选的原因是因为用户运行命令
> myscript ~/files/stuff/dir/
我希望它仍然有用。而且,就目前而言,如果我使用尾部斜杠运行该命令,它会根据需要输出。
那么,为什么我的?(/)
不起作用?基于我读过的所有内容,这应该是正确的语法,我也尝试过其他一些变体,但都无济于事。
感谢。
答案 0 :(得分:4)
that other guy's helpful answer解决了你的直接问题,但有两件事毫无价值:
使用不带引号的字符串变量(for file in $files
)枚举文件名是不明智的,因为sjsam's helpful answer指出:它会破坏带有嵌入空格和文件名看起来像globs的文件名;如上所述,将文件名存储在数组中是一个可靠的选择。
没有必要更改全局shell选项shopt -s extglob
:参数扩展可以嵌套,因此以下方法可以在不更改shell选项的情况下工作:
# Sample values:
file='dir/sub-dir/joe'
set -- 'dir/' # set $1; value 'dir' would have the same effect.
filename=${file#${1%/}} # -> '/sub-dir/joe'
内部参数展开${1%/}
会从%
中移除尾随(/
)$1
,如果有的话。
答案 1 :(得分:3)
我建议您将files
更改为数组,这可能是可能包含空格的非标准文件名的解决方法。
files=("dir/A/B" "dir/B" "dir/C")
for filename in "${files[@]}"
do
echo ${filename##dir/} #replace dir/ with your param.
done
<强>输出强>
A/B
B
C
答案 2 :(得分:2)
这里是来自man bash
的文档&#34;参数扩展&#34;:
${parameter#word}
${parameter##word}
Remove matching prefix pattern. The word is
expanded to produce a pattern just as in pathname
expansion. If the pattern matches the beginning of
the value of parameter, then the result of the
expansion is the expanded value of parameter with
the shortest matching pattern (the ``#'' case) or
the longest matching pattern (the ``##'' case)
deleted.
由于#
尝试删除最短匹配,因此它永远不会包含任何尾随的可选部分。
您可以改为使用##
:
filename=${file##${1}?(/)}
根据脚本的功能及其工作原理,您也可以将其重写为cd
到目录,以便始终使用相对于.
的路径