Normalizing Path Names with Bash

本文介绍了一个bash脚本函数,用于移除路径中的冗余符号如/./ 和 dir/..,并提供两种实现方式:一种利用bash的正则表达式,另一种采用sed命令。此外,还展示了如何运行脚本进行测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Regular expressions were introduced in bash 3.0. Bash 3.2 changed regular expression handling slightly in that quotes around regular expressions became part of the regular expression. So, if you have a version of bash (with regular expression support) and the code doesn't work, put the regular expression in the while loop in quotes.

The entire function and some test code follows:

#!/bin/bash
#
# Usage: normalize_path PATH
#
# Remove /./ and dir/.. sequences from a pathname and write result to stdout.

function normalize_path()
{
    # Remove all /./ sequences.
    # 这个替代的表达式不能工作的很好

    # 比如 /./ . /./ . /. 这样的形式 只能变成  /  . /   ./.

    local   path=${1////./////}
   
    # Remove dir/.. sequences.

    # =~ 是bash中用于正则表达式匹配的 运算符
    while [[ $path =~ ([^/][^/]*//././) ]]
    do

       # BASH_REMATCH[0] 表示匹配上的字符串
        path=${path/${BASH_REMATCH[0]}/}
    done
    echo $path
}

 

 

# $0 类似c语言的argv[0]

# $* 表示 所有的参数,不包括arg[0]

# $@ 表示 所有的参数

# 但是我们经过测试,我发现 $* 是一个全局的概念 也就是将所有的参数算成了一个整体

# 所以在for循环中 使用的是 $@ 而不是 $*

# $# 表示 参数个数


if [[ $(basename $0 .sh) == 'normalize_path' ]]; then
    if [[ "$*" ]]; then
        for p in "$@"
        do
            printf "%-30s => %s/n" $p $(normalize_path $p)
        done
    else
        for p in /test/../test/file test/../test/file .././test/../test/file
        do
            printf "%-30s => %s/n" $p $(normalize_path $p)
        done
    fi
fi


#####################################################################

# vim: tabstop=4: shiftwidth=4: noexpandtab:
# kate: tab-width 4; indent-width 4; replace-tabs false;

Since, older versions of bash don't support regular expressions the second version does the same thing using sed instead:

#!/bin/bash
#
# Usage: normalize_path PATH
#
# Remove /./ and dir/.. sequences from a pathname and write result to stdout.

function normalize_path()
{
    # Remove all /./ sequences.
    local   path=${1////./////}
   
    # Remove first dir/.. sequence.
    local   npath=$(echo $path | sed -e 's;[^/][^/]*//././;;')
   
    # Remove remaining dir/.. sequence.
    while [[ $npath != $path ]]
    do
        path=$npath
        npath=$(echo $path | sed -e 's;[^/][^/]*//././;;')
    done
    echo $path
}

if [[ $(basename $(basename $0 .sh) .old) == 'normalize_path' ]]; then
    if [[ "$*" ]]; then
        for p in "$@"
        do
            printf "%-30s => %s/n" $p $(normalize_path $p)
        done
    else
        for p in /test/../test/file test/../test/file .././test/../test/file
        do
            printf "%-30s => %s/n" $p $(normalize_path $p)
        done
    fi
fi


#####################################################################

# vim: tabstop=4: shiftwidth=4: noexpandtab:
# kate: tab-width 4; indent-width 4; replace-tabs false;

You can run the script directly and it runs a few tests:

$ bash normalize_path.sh
/test/../test/file             => /test/file
test/../test/file              => test/file
.././test/../test/file         => ../test/file

You can also pass in test cases on the command line:

$ bash normalize_path.sh ../d1/./d2/../f1 a/b/c/../d/../e
../d1/./d2/../f1               => ../d1/f1
a/b/c/../d/../e                => a/b/e

Normalized path names are never necessary but they're often easier to comprehend at a glance.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值