【问题标题】:Getting Short-Filename of Command-Line Argument from Batch-File从批处理文件中获取命令行参数的短文件名
【发布时间】:2011-01-12 10:43:52
【问题描述】:

批处理文件中的以下命令无法按预期/希望工作:

    echo %~nxs1


这是我想要得到的示例显示:

C:\>type test.bat
@dir /b %1
@echo %~nxs1

C:\>test "C:\Documents and Settings\All Users\ntuser.dat"
ntuser.dat
NTUSER.DAT

C:\>test "C:\Documents and Settings\All Users\ntuser.data"
ntuser.data
NTUSER~1.DA~

C:\>test "C:\Documents and Settings\All Users\ntuser.dat.baz"
ntuser.dat.baz
NTUSER~1.BAZ

C:\>test "C:\Documents and Settings\All Users\foo.bar.baz"
File Not Found
foo.bar.baz (or FOO~1.BAZ or whatever, doesn’t really matter since
             file does not exist, though latter would be nice)

相反,我得到的是以下内容(取决于分配的短文件名):

C:\>type test.bat
@dir /b %1
@echo %~nxs1

C:\>test "C:\Documents and Settings\All Users\ntuser.dat"
ntuser.dat
s\ntuser.dat

C:\>test "C:\Documents and Settings\All Users\ntuser.data"
ntuser.data
s\ntuser.data

C:\>test "C:\Documents and Settings\All Users\ntuser.dat.baz"
ntuser.dat.baz
z

C:\>test "C:\Documents and Settings\All Users\foo.bar.baz"
File Not Found
s\foo.bar.baz



基本上,我需要将文件名传递给 BAT 文件并让脚本将其作为短文件名获取(例如显示),但只有文件名和扩展名,没有驱动器或路径。

FOR 的帮助信息以 %~fsI 为例,但它具有整个路径作为短文件名,而不仅仅是文件。有谁知道如何组合 %~ 中的 S 参数而不获取整个路径?


非常感谢。



更新

  1. 我不是在寻找其他语言的解决方案,我需要 BAT 命令才能工作。

  2. 它似乎适用于其他人,所以我正在检查它是否是某种替代配置问题。我目前正在测试命令处理器扩展是否可能是原因。

  3. 如果扩展被禁用(显然),它根本不起作用,所以我继续假设它是在后续服务包中修复的错误(我测试的系统是 XP SP1)。我今天正在测试 SP2 和 SP3……

【问题讨论】:

  • 执行您的示例脚本没有问题。
  • 你的脚本在 WinXP 上对我有效

标签: batch-file filenames command-line-arguments substitution


【解决方案1】:

还有另一种方法,在VS中编译这段代码:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

namespace ConvFN
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 3)
            {
                if ((args[2].Length > 1) && System.IO.File.Exists(args[2]))
                {
                    if (args[1].Equals("-l")) Console.WriteLine(ShortLongFName.GetLongPathName(args[2]));
                    if (args[1].Equals("-s")) Console.WriteLine(ShortLongFName.ToShortPathName(args[2]));
                }
            }
        }
    }

    public class ShortLongFName
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern uint GetShortPathName(
           [MarshalAs(UnmanagedType.LPTStr)]
   string lpszLongPath,
           [MarshalAs(UnmanagedType.LPTStr)]
   StringBuilder lpszShortPath,
           uint cchBuffer);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.U4)]
        private static extern int GetLongPathName(
            [MarshalAs(UnmanagedType.LPTStr)]
        string lpszShortPath,
            [MarshalAs(UnmanagedType.LPTStr)]
        StringBuilder lpszLongPath,
            [MarshalAs(UnmanagedType.U4)]
        int cchBuffer);

        /// <summary>
        /// Converts a short path to a long path.
        /// </summary>
        /// <param name="shortPath">A path that may contain short path elements (~1).</param>
        /// <returns>The long path.  Null or empty if the input is null or empty.</returns>
        internal static string GetLongPathName(string shortPath)
        {
            if (String.IsNullOrEmpty(shortPath))
            {
                return shortPath;
            }

            StringBuilder builder = new StringBuilder(255);
            int result = GetLongPathName(shortPath, builder, builder.Capacity);
            if (result &gt; 0 && result &lt; builder.Capacity)
            {
                return builder.ToString(0, result);
            }
            else
            {
                if (result &gt; 0)
                {
                    builder = new StringBuilder(result);
                    result = GetLongPathName(shortPath, builder, builder.Capacity);
                    return builder.ToString(0, result);
                }
                else
                {
                    throw new FileNotFoundException(
                        string.Format(
                        CultureInfo.CurrentCulture,
                        "{0} Not Found",
                        shortPath),
                        shortPath);
                }
            }
        }
        /// <summary>
        /// The ToLongPathNameToShortPathName function retrieves the short path form of a specified long input path
        /// </summary>
        /// <param name="longName">The long name path</param>
        /// <returns>A short name path string</returns>
        public static string ToShortPathName(string longName)
        {
            uint bufferSize = 256;

            // don´t allocate stringbuilder here but outside of the function for fast access
            StringBuilder shortNameBuffer = new StringBuilder((int)bufferSize);

            uint result = GetShortPathName(longName, shortNameBuffer, bufferSize);

            return shortNameBuffer.ToString();
        }
    }
}

将其添加到名为 ConvFN 的控制台 C# 项目中并构建它。然后从批处理文件中调用 ConvFN -s %1 ,其中 %1 参数是一个长文件名,它将输出等效的短文件名......反过来,ConvFN -l %1 ,其中 %1 是短文件名和它将输出等效的长文件名。

此代码取自 pinvoke.net。

【讨论】:

    【解决方案2】:

    看看this forum post。代码如下:

    %~snx
    s ... short 
    n ... name
    x ... extension
    

    【讨论】:

    • 是的,我知道。我说它没有按预期工作,并确认这是 XP SP1 中的一个错误。
    【解决方案3】:

    1- 将代码保存在 ShortFileName.Vbs

    2- 拖放任何文件夹或文件到此脚本

        Set fso=CreateObject("Scripting.FileSystemObject")
        ' Is object a file or folder?
    
        If fso.FolderExists(WScript.Arguments(0)) Then
           'The dropped stuff is a folder
           Set objFolder = fso.GetFolder(WScript.Arguments(0))
           rtrn = InputBox("Short path is :", "SHORT PATH", objFolder.ShortPath)
        End If
    
        If fso.FileExists(WScript.Arguments(0)) Then
           'The dropped stuff is a file
           Set objFile = fso.GetFile(WScript.Arguments(0))
           rtrn = InputBox("Short path is :", "SHORT PATH", objFile.ShortPath)
        End If
    

    【讨论】:

      【解决方案4】:

      嗯,我刚刚确认了。我使用 XP SP1、SP2 和 SP3 中的 CMD.EXE 以及 SP2 VM 安装测试了该脚本。它在 SP1 版本中给出了上述错误结果,但在 SP2 和 SP3 版本中正常工作。所以这确实是一个已修复的错误。对于遇到此问题的任何其他人,SP2+ 中的 CMD.EXE 文件可以毫无问题地放入 SP1 安装中(假设更新不可行)。

      【讨论】:

      • 哇!没有解释的否决票非常有用!你们(不管是谁做的)摇滚!
      • 哦,对正确答案投反对票简直是愚蠢的。我想出的答案实际上是正确的,任何遇到相同问题的人都可以得到他们正在寻找的答案,但是一些 d-bag 否决了它(甚至没有留下评论来解释自己!) ,所以路人可能会认为这是不正确的。 :roll:
      【解决方案5】:

      执行您的批处理没有问题。希望有人能尽快帮助你。但是,当您使用它时,这里有一个使用 Vbscript 完成的替代方案,我认为您应该熟悉它。

      Set objArgs = WScript.Arguments
      strFile = objArgs(0)
      WScript.Echo CreateObject("Scripting.FileSystemObject").GetFile(strFile).ShortName
      

      在命令行(或您的批处理)上,这样调用它

      C:\test>cscript //nologo getshortname.vbs "C:\Documents and Settings\All Users\Desktop\shortcut.lnk"
      shortcut.lnk
      

      【讨论】:

        猜你喜欢
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 2010-11-20
        • 2012-02-28
        • 1970-01-01
        • 1970-01-01
        • 2021-01-20
        相关资源
        最近更新 更多