How to safely add the file name to the argument of the path to the Windows folder?

Suppose I have a script package that expects a folder path in argument %1 . I want to add the file name to the path and use it in a command. Is there an easy way to do this in such a way that it is reliable in all situations?

I don't want PUSHD %1 and just ignore the path later. Suppose my logic requires that the current directory remain unchanged.

The problem is that argument %1 may or may not have a trailing backslash - i.e. c:\path or c:\path\ .

Usually I can just use "%~1\file.ext" because Windows treats "c:\path\file.ext" and "c:\path\\file.ext" identically.

But there is one unpleasant case - c:\

The following commands create this error: The filename, directory name, or volume label syntax is incorrect.

 dir "c:\\file.ext" del "c:\\file.ext" 

Strange, these commands work very well:

 if exist "c:\\file.ext" echo OK echo text>"c:\\file.ext" copy "c:\\file.ext" "somePath" xcopy "c:\\file.ext" "somePath" 

There is another problematic case - c: that is, the current directory on the C: drive will give the wrong result if I add a backslash. "c:file.ext" does not match "c:\file.ext" .

Is there an easy way to safely add a file name to any given folder path?

I do not deal with UNC paths, as I do not use them very often, and I believe that there are some commands that do not play well with UNC paths.

Note. This is the case when I submit a paired question and answer. This problem has been a thorn on my side for a number of years, and I recently discovered a simple solution that I thought might interest others.

+6
source share
3 answers

EDIT - response changed to MC ND comment

The solution is so simple :-) "%~f1.\file.ext"

Windows file names cannot end in . or <space> , so all Windows commands simply ignore trailing ones . and <space> file / folder names.

And one . following a backslash represents the current directory at this location.

Suppose the current working directory is c:\test , then the table below shows how the various values ​​are resolved:

 "%~1" | "%~f1.\file.ext" | equivalent to -------------+------------------------+------------------------ "c:\folder\" | "c:\folder\.\file.ext" | "c:\folder\file.ext" | | "c:\folder" | "c:\folder.\file.ext" | "c:\folder\file.ext" | | "c:\" | "c:\.\file.ext" | "c:\file.ext" | | "c:" | "c:\test.\file.ext" | "c:\test\file.ext" | | "." | "c:\test.\file.ext" | "c:\test\file.ext" | | ".." | "c:\.\file.ext" | "c:\file.ext" | | <no value> | "c:\test.\file.ext" | "c:\test\file.ext" I hadn't thought of this case until I saw MC ND answer 

You can easily reduce the expression in canonical equivalent form using the FOR loop:

 for %%A in ("%~f1.\file.ext") do echo "%%~fA" 

According to Harry Johnston in his comment, this solution does not work with UNC root paths ( \\server\shareName ) or long paths ( \\?\c:\somePath ). See MC ND's answer if you need to support any of these cases. Harry Johnston's answer is simpler, but it does not support the case of missing arguments.

+6
source

I see no way to make it work in all cases. Your solution will handle all cases of local paths, but to handle UNC or long paths, it seems like you need to fix the path first and then add the file data.

 @echo off setlocal enableextensions disabledelayedexpansion for /f "delims=" %%a in ("%~f1." ) do for /f "delims=" %%b in ("%%~fa\file.ext" ) do echo "%%~fb" 

This "should" handle local, network, or long paths (is the reason for for /f ? ), Both absolute and relative, and the possibility of not specifying a path on the command line.

+2
source

Since ~ f excludes a few backslashes, I think this works as well as the original sentence, and also seems to handle roots and long paths correctly:

 for /F "delims=" %%i in (%~f1\file.ext) do set filename=%%~fi 
+2
source

Source: https://habr.com/ru/post/977614/


All Articles