开发者

bash equivalent of Python's os.path.normpath?

开发者 https://www.devze.com 2023-03-13 23:47 出处:网络
What\'s the bash equivalent to os.path.normpath? S开发者_高级运维pecifically I\'m interested in removing the leading ./ given when executing find.

What's the bash equivalent to os.path.normpath? S开发者_高级运维pecifically I'm interested in removing the leading ./ given when executing find.

matt@stanley:~/src/libtelnet-0.20/test$ find
.
./Makefile
./Makefile.in
./Makefile.am
...


Well, for that, you can simply pipe the output through sed, you don't have to normalise the entire path:

your_command_goes_here | sed 's?^\./??'

That will get rid of all ./ sequences at the start of a line.

The following transcript shows this in action:

pax$ find -name 'qq*sh'
./qq.ksh
./qq.sh
./qq.zsh
./qq2.sh
./qq2.zsh
./qqq/qq.sh

pax$ find -name 'qq*sh' | sed 's?^./??'
qq.ksh
qq.sh
qq.zsh
qq2.sh
qq2.zsh
qqq/qq.sh

As you can see, I have a fairly intuitive naming standard for my temporary shell scripts :-)


I'm struggling to find a case where I'd want to use os.path.normpath. On a system that has symbolic links, such as unix or Windows, the value that it returns may not designate the same file:

$ mkdir /tmp/one /tmp/one/two
$ ln -s /tmp/one/two /tmp/foo
$ python -c 'import os.path; print os.path.normpath("/tmp/foo/..")'
/tmp
$ ls /tmp/foo/..
two

/tmp/foo/.. is /tmp/one, not /tmp!

On Linux, readlink -- "$filename" normalizes all symbolic links in a path. The file name it returns designates the same file as $filename at the time the command is executed (it might not, later, if one of the symlinks involved is changed). But most of the time, that's not necessary: just keep $filename as it is.

If you want to remove a ./ prefix for cosmetic reasons, just strip it specifically.

filename=${filename#./}
find | sed -e 's!^\./!!'


I usually do this by using find's -printf argument.

The following works fine if you're searching in multiple paths:

find path1 path2

The following works fine if you're searching in .:

find -printf '%P\n'

If you have a mixed paths (e.g. find path1 path2 .), you'd have to use sed.


How about:

newpath=`echo -n "$oldpath" | python -c 'import sys, os; print os.path.normpath(sys.stdin.readline())'`

?

I do not think there is any built-in bash function to do everything Python's normpath does. You might be better off describing exactly what transformation you want to perform.


Write something like this:

normpath() {
    [[ -z "$1" ]] && return

    local skip=0 p o c

    p="$1"
    # check if we have absolute path and if not make it absolute
    [[ "${p:0:1}" != "/" ]] && p="$PWD/$p"

    o=""
    # loop on processing all path elements
    while [[ "$p" != "/" ]]; do
        # retrive current path element
        c="$(basename "$p")"
        # shink our path on one(current) element
        p="$(dirname "$p")"

        # basename/dirname correct handle multimple "/" chars
        # so we can not warry about them

        # skip elements "/./" 
        [[ "$c" == "." ]] && continue
        if [[ "$c" == ".." ]]; then
            # if we have point on parent dir, we must skip next element
            # in other words "a/abc/../c" must become "a/c"
            let "skip += 1"
        elif [[ 0 -lt $skip ]]; then
            # skip current element and decrease skip counter
            let "skip -= 1"
        else
            # this is normal element and we must add it to result
            [[ -n "$o" ]] && o="/$o"
            o="$c$o"
        fi
    done

    # last thing - restore original absolute path sign
    echo "/$o"
}


I found it: it's called realpath! Type something like:

realpath ..   # the most interesting thing

or

realpath .    # equivalent to `pwd' and to `echo $PWD'

and enjoy!

Unlike os.path.normpath, realpath requires the path to exist. If you just want to normalise it as a string realpath -m can be used.


Possible duplicate here. But if you are just interested in striping off leading ./ you could just do

find -type f | sed 's/^\.\///'
0

精彩评论

暂无评论...
验证码 换一张
取 消