10

我理解修饰符# ## % %%,但我不知道是否可以像在 tcsh 中那样将它们链接在一起。

tcsh 中的示例

set f = /foo/bar/myfile.0076.jpg
echo $f:r:e
--> 0076

echo $f:h:t
--> bar

在 bash 中,我想知道如何执行以下操作:

echo ${f%.*#*.}

在一行中。

我的目标是能够在需要时在命令行上以各种方式操作文件名。我不是想为一个特定案例编写脚本。因此,如果有一种方法可以链接这些修饰符,或者可能有另一种方法,那么我很想知道。谢谢

4

3 回答 3

7

在 bash 中,您可以嵌套参数扩展,但只能${parameter#word}.

例如:

$ var="foo.bar.baz"; echo ${var%.*}
foo.bar
$ var="foo.bar.baz"; echo ${var#foo.bar}
.baz
$ var="foo.bar.baz"; echo ${var#${var%.*}}
.baz

要使用纯参数扩展做你想做的事,你需要有一个像这样的临时变量:

$ var="/foo/bar/myfile.0076.jpg"; tmp=${var#*.}; out=${tmp%.*}; echo $out
0076

但是,如果您愿意使用set内置函数,那么您实际上可以通过巧妙地使用搜索/替换参数扩展来一次性访问所有字段,如下所示:

$ var="/foo/bar/myfile.0076.jpg"; set -- ${var//[.\/]/ }; echo $4
0076
于 2011-02-28T20:32:22.697 回答
3

您可以尝试实现的一种方法是使用 Bash 的正则表达式(版本 3.2 及更高版本)。

f=/foo/bar/myfile.0076.jpg
pattern='/([^/]*)/[^/]*\.([0-9]*)\.'
[[ $f =~ $pattern ]]
echo ${BASH_REMATCH[1]}    # bar
echo ${BASH_REMATCH[2]}    # 0076

您可以按顺序应用大括号扩展运算符:

f=/foo/bar/myfile.0076.jpg
r=${f%.*}  # remove the extension
r=${r#*.}  # remove the part before the first (now only) dot
echo $r    # 0076
r=${f%/*}  # similar, but use slash instead of dot
r=${r##*/}
echo $r    # bar

另一种方法是将大括号扩展与扩展 glob 结合起来:

shopt -s extglob
f=/foo/bar/myfile.0076.jpg
r=${f/%*([^0-9])}    # remove the non-digits from the beginning
r=${r/#*([^0-9])}    # remove the non-digits from the end
echo $r              # 0076
r=${f/#*(\/*([^\/])\/)}    # remove the first two slashes and what's between them
r=${r/%\/*(?)}             # remove the last slash and everything after it
echo $r                    # bar

编辑:

这是我的 Bash 函数,它们执行basenamedirname. 它们以类似于那些实用程序的方式处理边缘情况。

bn ()
{
    [[ $1 == / ]] && echo / || echo "${1##*/}"
}

dn ()
{
    [[ -z ${1%/*} ]] && echo / || {
        [[ $1 == .. ]] && echo . || echo "${1%/*}"
    }
}
于 2011-03-01T01:28:01.390 回答
1

我找到了一个非常接近 tcsh 文件名修饰符的简单性的解决方案。我写了 4 个函数并将它们放在 .bashrc 中。

e() # the extension
E() # everything but the extension
t() # the tail - i.e. everything after the last /
T() # everything but the tail (head)

定义在最后。

这些函数可以接受如下参数:

f=foo/bar/my_image_file.0076.jpg
e $f
--> jpg
E $f
--> foo/bar/my_image_file.0076

或接受来自管道的输入,这是我真正想要的 tcsh 功能:

echo $f|E|e
--> 0076

或者当然,一个组合:

T $f|t
--> bar

我突然意识到它将通过管道接受许多文件:

ls foo/bar/
--> my_image_file.0075.jpg  my_image_file.0076.jpg
ls foo/bar/ |E|e
--> 0075
--> 0076

定义:

#If there are no args, then assume input comes from a pipe.

function e(){
    if [ $# -ne 0 ]; then
        echo ${1##*.}  
    else
        while read data; do
            echo  ${data##*.}   ; 
        done
    fi
}

function E(){
    if [ $# -ne 0 ]; then
        echo ${1%.*} 
    else
        while read data; do
            echo ${data%.*}
        done
    fi
}

function t(){
    if [ $# -ne 0 ]; then
        echo ${1##*/}  
    else
        while read data; do
            echo  ${data##*/}   ; 
        done
    fi
}

function T(){
    if [ $# -ne 0 ]; then
        echo ${1%/*} 
    else
        while read data; do
            echo ${data%/*}
        done
    fi
}
于 2011-03-01T22:23:06.430 回答