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/^\.\///'
精彩评论