What's the bash equivalent to os.path.normpath
? Specifically I'm interested in removing the leading ./
given when executing find
.
matt@stanley:~/src/libtelnet-0.20/test$ find . ./Makefile ./Makefile.in ./Makefile.am ...
What's the bash equivalent to os.path.normpath
? Specifically 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!^\./!!'
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.
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.
Possible duplicate here. But if you are just interested in striping off leading ./ you could just do
find -type f | sed 's/^\.\///'