我有一个不错的控制台文件管理器(Senh Liu 的 eXtreme),它将短路径/文件名作为变量传递给 menu.bat。
如何生成完整的文件夹名称 + 长文件名?
示例:
我尝试了以下方法:
SET my_file=%~2
:echo %my_file%
生产:"P:\MYPROG~1\SHELLS\ZBACKUP\REFSTO~1.BAL"
FOR /F "tokens=* USEBACKQ" %%F IN (`dir /B %2`) DO SET my_file=%%~fF
:echo %my_file%
生产:"P:\MYPROG~1\SHELLS\zBackup\RefsToMyData.bal"
FOR /F "tokens=* USEBACKQ" %%F IN (`dir /B %2`) DO SET my_file=%%~dpnxF
:echo %my_file%
生产:"P:\MYPROG~1\SHELLS\zBackup\RefsToMyData.bal"
最佳答案
以下应该适用于任何有效路径,只要它是 不是 UNC 路径。路径可以是绝对的,也可以是相对的。它可以使用短文件名或长文件名(或混合)。路径可以指文件夹或文件。
结果将以 \
结尾如果是文件夹,则没有 \
最后,如果它是一个文件。:getLongPath
例程需要一个 inputPath 变量名作为第一个参数,一个可选的返回变量名作为第二个参数。 inputPath 变量应包含有效路径。如果未指定返回变量,则结果将显示在屏幕上(用引号括起来)。如果指定了返回变量,则在变量中返回结果(不带引号)。
如果您正在返回一个变量,则只应在禁用延迟扩展时调用该例程。如果在启用延迟扩展的情况下调用,那么如果结果包含 !
,结果将被破坏。性格。
测试用例(仅适用于我的机器)在脚本的顶部,实际的例程在底部。
@echo off
setlocal
for %%F in (
"D:\test\AB2761~1\AZCFE4~1.TXT"
"AB2761~1\AZCFE4~1.TXT"
"D:\test\AB2761~1\ZZCE57~1\"
"D:\test\a b\a z.txt"
"D:\test\a b\z z"
"."
"\"
"x%%&BAN~1\test"
"x%% & bang!\test"
) do (
echo(
echo resolving %%F
set "shortPath=%%~F"
call :getLongPath shortPath longPath
set longPath
)
echo(
echo(
set "shortPath=D:\test\AB2761~1\AZCFE4~1.TXT"
set shortPath
echo Calling :getLongPath with with no return variable
call :getLongPath shortPath
exit /b
:getLongPath path [rtnVar]
setlocal disableDelayedExpansion
setlocal enableDelayedExpansion
for %%F in ("!%~1!") do (
endlocal
set "sourcePath=%%~sF"
set "sourceFile=%%~nxF"
)
if not exist "%sourcePath%" (
>&2 echo ERROR: Invalid path
exit /b 1
)
set "rtn="
2>nul cd "%sourcePath%" || (
cd "%sourcePath%\.."
for /f "eol=: delims=" %%F in ('dir /b /a-d "%sourceFile%"') do set "rtn=%%F"
)
:resolveFolders
for %%F in ("%cd%") do (
cd ..
set "folder=%%~nxF"
)
if defined folder for /f "eol=: delims=" %%: in ('dir /b /ad') do (
if /i "%%~snx:" equ "%folder%" (
set "rtn=%%:\%rtn%"
goto :resolveFolders
)
)
set "rtn=%cd%%rtn%
( endlocal
if "%~2" equ "" (echo "%rtn%") else set "%~2=%rtn%"
)
=== 输出 ===
resolving "D:\test\AB2761~1\AZCFE4~1.TXT"
longPath=D:\test\a b\a z.txt
resolving "AB2761~1\AZCFE4~1.TXT"
longPath=D:\test\a b\a z.txt
resolving "D:\test\AB2761~1\ZZCE57~1\"
longPath=D:\test\a b\z z\
resolving "D:\test\a b\a z.txt"
longPath=D:\test\a b\a z.txt
resolving "D:\test\a b\z z"
longPath=D:\test\a b\z z\
resolving "."
longPath=D:\test\
resolving "\"
longPath=D:\
resolving "x%&BAN~1\test"
longPath=D:\test\x% & bang!\test\
resolving "x% & bang!\test"
longPath=D:\test\x% & bang!\test\
shortPath=D:\test\AB2761~1\AZCFE4~1.TXT
Calling :getLongPath with with no return variable
"D:\test\a b\a z.txt"
如果你想运行上面的代码,那么我建议你完全删除
@echo off
之间的所有测试场景代码。和 :getLongPath
.然后您可以简单地调用脚本,将任何有效路径作为第一个参数传递。结果应该打印正确的长路径。我很惊讶使用批处理来解决这个问题是多么困难。我认为使用 JScript 或 VBS 并不容易(实际上,Ansgar 找到了一个不错的 VBS 解决方案)。但我喜欢 Ansgar 的简单 PowerShell 解决方案 - 简单得多。
更新
我发现了一个模糊的情况,如果从 FOR 循环中调用上述代码将失败,并且路径中恰好包含 FOR 变量。它也不会正确地将带有通配符的路径报告为错误,并且当路径包含
!
时,它无法在启用延迟扩展的情况下工作。 .所以我在下面创建了一个修改版本。我非常有信心它应该真正适用于所有情况,除了 UNC 路径,并且路径中可能没有 unicode。我将它打包为一个易于调用的过程,并带有内置文档。它可以保留为独立脚本,也可以合并到更大的脚本中。
@echo off
:getLongPath
:::
:::getLongPath PathVar [RtnVar]
:::getLongPath /?
:::
::: Resolves the path contained in PathVar into the full long path.
::: If the path represents a folder then it will end with \
:::
::: The result is returned in variable RtnVar.
::: The result is echoed to the screen if RtnVar is not specified.
:::
::: Prints this documentation if the first argument is /?
if "%~1" equ "" (
>&2 echo ERROR: Insufficient arguments. Use getLongPath /? to get help.
exit /b 1
)
if "%~1" equ "/?" (
for /f "delims=" %%A in ('findstr "^:::" "%~f0"') do (
set "ln=%%A"
setlocal enableDelayedExpansion
echo(!ln:~3!
endlocal
)
exit /b 0
)
setlocal
set "notDelayed=!"
setlocal disableDelayedExpansion
setlocal enableDelayedExpansion
for /f "eol=: delims=" %%F in ("!%~1!") do (
endlocal
set "sourcePath=%%~sF"
set "sourcePath2=%%F"
set "sourceFile=%%~nxF"
)
if not exist "%sourcePath%" (
>&2 echo ERROR: Invalid path
exit /b 1
)
set "sourcePath3=%sourcePath2:**=%"
set "sourcePath3=%sourcePath3:?=%"
if "%sourcePath3%" neq "%sourcePath2%" (
>&2 echo ERROR: Invalid path
exit /b 1
)
set "rtn="
2>nul cd "%sourcePath%" || (
cd "%sourcePath%\.."
for /f "eol=: delims=" %%F in ('dir /b /a-d "%sourceFile%"') do set "rtn=%%F"
)
:resolveFolders
for %%F in ("%cd%") do (
cd ..
set "folder=%%~nxF"
)
if defined folder for /f "delims=: tokens=1,2" %%A in ("%folder%:%rtn%") do for /f "eol=: delims=" %%F in ('dir /b /ad') do (
if /i "%%~snxF" equ "%%A" (
set "rtn=%%F\%%B"
goto :resolveFolders
)
)
set "rtn=%cd%%rtn%"
if not defined notDelayed set "rtn=%rtn:^=^^%"
if not defined notDelayed set "rtn=%rtn:!=^!%"
if not defined notDelayed (set "!=!==!") else set "!="
for %%A in ("%rtn%") do (
endlocal
endlocal
if "%~2" equ "" (echo %%~A%!%) else set "%~2=%%~A"!
)
我还将 Ansgar 的 VBS 改编成混合 JScript/批处理脚本。它应该提供与上面纯批处理脚本相同的结果,但 JScript 更易于遵循。
@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment
@echo off
:getLongpath
:::
:::getLongPath PathVar [RtnVar]
:::getLongPath /?
:::
::: Resolves the path contained in PathVar into the full long path.
::: If the path represents a folder then it will end with \
:::
::: The result is returned in variable RtnVar.
::: The result is echoed to the screen if RtnVar is not specified.
:::
::: Prints this documentation if the first argument is /?
::************ Batch portion ***********
if "%~1" equ "" (
>&2 echo ERROR: Insufficient arguments. Use getLongPath /? to get help.
exit /b 1
)
if "%~1" equ "/?" (
for /f "delims=" %%A in ('findstr "^:::" "%~f0"') do (
set "ln=%%A"
setlocal enableDelayedExpansion
echo(!ln:~3!
endlocal
)
exit /b 0
)
setlocal
set "notDelayed=!"
setlocal disableDelayedExpansion
set "rtn="
for /f "delims=" %%A in ('cscript //E:JScript //nologo "%~f0" %*') do set "rtn=%%A"
if not defined rtn exit /b 1
if not defined notDelayed set "rtn=%rtn:^=^^%"
if not defined notDelayed set "rtn=%rtn:!=^!%"
if not defined notDelayed (set "!=!==!") else set "!="
for %%A in ("%rtn%") do (
endlocal
endlocal
if "%~2" equ "" (echo %%~A%!%) else set "%~2=%%~A"!
)
exit /b 0
************ JScript portion ***********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var fso=WScript.CreateObject("Scripting.FileSystemObject");
var app=WScript.CreateObject("Shell.Application");
var inPath=env(WScript.Arguments.Item(0));
var folder="";
var f;
if (fso.FileExists(inPath)) {
f=fso.GetFile(inPath);
}
else if (fso.FolderExists(inPath)) {
folder="\\"
f=fso.GetFolder(inPath);
if (f.IsRootFolder) {
WScript.StdOut.WriteLine(f.Path);
WScript.Quit(0);
}
}
else {
WScript.StdErr.WriteLine('ERROR: Invalid path');
WScript.Quit(1);
}
WScript.StdOut.WriteLine( app.NameSpace(f.ParentFolder.Path).ParseName(f.Name).Path + folder);
关于batch-file - 从短文件名获取完整路径和长文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18654988/