'''`file normalize`''' normalizes a filename. ** Synopsis ** : '''file normalize''' ''name'' ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/file.htm%|%official reference]: ** Description ** Returns a normalized filename for ''name''. A normalized filename is an [file pathtype%|%absolute] filename that 1. Contains no `.` or `..` components. 1. Contains no consecutive `/` characters other than the initial two `/` characters of a filename that begins with exactly two `/` characters. 1. Contains no symbolic links, except that if ''name'' refers to a symbolic link, the final component of the normalized filename remains a symbolic link to afford operations on the link itself, such as `[file delete]`, `[file rename]`, or `[file copy]`. 1. Is in the "standard" format for the native platform, On [Microsoft Windows%|%Windows] this is the case-preserved long form of the filename. Because `file normalize` transforms embedded symbolic links, it may be overkill for the purpose of just transforming a filename into an absolute filename. Instead, use `[file join]`, perhaps with `[pwd]`. ** See Also ** [file]: [file nativename]: [file join]: [file readlink]: ** Bugs ** [http://sourceforge.net/tracker/?func=detail&atid=110894&aid=1194458&group_id=10894%|%1194458]: fixed in 8.4.11 ** Forward Compatibility ** [file forward compatibility]: `file normalize` emulation code taken from critcl.tcl, and added to the wiki in the hope that more people will use normalize, and move faster to 8.4 and later. ** Volume-Relative filenames ** Windows has the concept of a current directory per drive, a concept it inherited from DOS. From a Command Prompt you can do: ======none c: cd \winnt d: type c:setup.log ====== and see setup.log from the current directory \winnt on drive c:. It's an obscure featrue, and it doesn't work in Windows Explorer. Therefore, if the current working directory is `c:\winnt`, 2023-08 JMN Has the ability to access this ever been available in Tcl? That 'file pathtype' returns 'volumerelative' only really seems useful in the context of a 'cd' command which can preserve this information when switching volumes. I couldn't find anything in twapi to retrieve this info. It would be great to have cd fixed in this regards. ====== file normalize c:setup.log ====== results in ====== C:/WINDOWS/WindowsUpdate.log ====== Prior to Tcl version 8.4.5, `[file normalize]` didn't handle volume relative filenames correctly: ====== file normalize c:a/b ====== resulted in `c:a/b` ** File normalize and Windows folder junctions ** 2013-01-08: All Tcl versions before 8.5.13, 8.6.0 have bugs with folder junctions, when the access rights are restricted [https://sourceforge.net/tracker/?func=detail&atid=110894&aid=3092089&group_id=10894%|%tcl-Bugs-3092089%|%], [https://sourceforge.net/tracker/?func=detail&atid=110894&aid=3587096&group_id=10894%|%tcl-Bugs-3587096%|%]. They are fixed in [https://core.tcl.tk/tcl/info/8a291bcb44%|%Tcl fossil Check-in 8a291bcb44%|%]. [HaO]: `file normalize` will resolve junctions of the Windows NTFS file system and return the filenames without the junctions, if there is a component after the junction. This is specially helpful, if the junction has less access rights than the direct way (which is the case for localized "program files" folders of Windows Vista). I took the habit, to pass any files in system folders by `file normalize` before accessing them. *** Example *** Create a folder, `C:\test2`, and a junction, `C:\test2_junction` to it. In a dos box with administrator rights: ======none C:\Windows\system32> cd c:\ C:\> mkdir test2 C:\> mklink /j test2_junction test2 ====== Now test `file normalize` in a wish console: ====== % file normalize c:/test2_junction c:/test2_junction % file normalize c:/test2_junction/test.txt c:/test2/test.txt ====== ** Resolving symlinks in the last component of a path ** To resolve symlinks in a path's final component (i.e., the target file or directory name itself) you can use the following trick: add `/something` to the path before normalizing it then strip the extra component away with `[file dirname]`. For example, ====== set resolvedArgv0 [file dirname [file normalize $argv0/___]]] ====== [dbohdan] 2015-05-12: This trick was implemented by [AK] in [Tclssg]'s [https://github.com/tclssg/tclssg/blob/master/ssg.tcl%|%main procedure] and I thought it deserved wider exposure. The credit is all [AK]'s. [PYK] 2015-05-12: This technique is also employed in [main script]. ** Alternative that leaves symlinks alone ** [mfriedrich] How to normalize a path without resolving symlinks? E.g. on Windows mapped network drives where the server uses NTFS junctions pointing to server disks and not to local disks. [AMG]: Try repeated [[[regsub]]]. Here's code from [Wibble], sans call to the Wibble-specific [[dehex]] command: ====== regsub -all {(?:/|^)\.(?=/|$)} $path / path while {[regsub {(?:/[^/]*/+|^[^/]*/+|^)\.\.(?=/|$)} $path "" path]} {} regsub -all {//+} /$path / path ====== ---- [MHo] 2016-02-12: Just realized that '''file normalize''' does not work as expected in the following special case: ====== % glob //?/UNC//wk101w0045/d$ -- * base-tcl-thread-win32-ix86.dll base-tcl-thread-win32-ix86.exe base-tcl8.6-thread-win32-ix86.dll base-tcl8.6-thread-win32..... % file normalize //?/UNC//wk101w0045/d$ D://?/UNC//wk101w0045/d$ % ====== In that case, a Driveletter is prepended, although it should'nt. //?/ is a valid prefix, as is //?//UNC. These are rarely used special cases, though. More important, the //?//... does NOT WORK AT ALL, if the given spec is a DFS-Link.... <> Tcl syntax | Command | File | Introspection