从批处理文件中获取命令行参数的短文件名

发布于 2024-08-20 09:54:34 字数 1682 浏览 11 评论 0原文

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

    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...

The following command in a batch file does not work as expected/hoped:

    echo %~nxs1

Here is a sample display of what I’m trying to get:

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)

Instead what I get is something like the following (depending on assigned short-filenames):

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

Basically, I need to pass a filename to a BAT file and have the script get (eg display) it as a short-filename, but only the filename and extension, no drive or path.

The help info for FOR gives %~fsI as an example, but that has the whole path as a short-filename, not just the file. Does anyone know how to combine the S parameter from %~ without getting the whole path?

Thanks a lot.

Updates

  1. I am not looking for a solution in a different language, I need the BAT command to work.

  2. It seems that it works for others, so I am checking to see if it is some kind of alternate configuration issue. I’m currently testing to see if Command Processor Extensions could be the cause.

  3. It won’t work at all if Extensions are disabled (obviously), so I’m going on the hypothesis that it is a bug that was fixed in a subsequent service pack (the system I tested on is XP SP1). I’m testing SP2 and SP3 today…

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

红ご颜醉 2024-08-27 09:54:34

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

Well I just confirmed it. I tested the script with CMD.EXE from XP SP1, SP2, and SP3 as well as an SP2 VM installation. It gave the aforementioned erroneous results with the SP1 version, but worked correctly in the SP2 and SP3 versions. So it is indeed a bug that was fixed. For anyone else who runs into this, the CMD.EXE file from SP2+ can be dropped into an SP1 installation without issue (assuming that an update is not feasible).

电影里的梦 2024-08-27 09:54:34

请查看此论坛帖子。代码如下:

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

Look at this forum post. The code looks like:

%~snx
s ... short 
n ... name
x ... extension
往事随风而去 2024-08-27 09:54:34

我执行你的批处理没有问题。希望有人能尽快帮助您。但是当您使用它时,这里有一个使用 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

I don't have a problem executing your batch. Hope someone can help you soon. But while you are at it, here's an alternative done with Vbscript, which i think you should get familiar with.

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

on the command line (or your batch), call it like this

C:\test>cscript //nologo getshortname.vbs "C:\Documents and Settings\All Users\Desktop\shortcut.lnk"
shortcut.lnk
请止步禁区 2024-08-27 09:54:34

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

1- Save the code in ShortFileName.Vbs

2- Drag n Drop any folder or file to this script

    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
江湖正好 2024-08-27 09:54:34

还有另一种方法可以做到这一点,在 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 > 0 && result < builder.Capacity)
            {
                return builder.ToString(0, result);
            }
            else
            {
                if (result > 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。

There is another way of doing this, compile this code in 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 > 0 && result < builder.Capacity)
            {
                return builder.ToString(0, result);
            }
            else
            {
                if (result > 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();
        }
    }
}

Add this into the Console C# project called ConvFN and build it. Then invoke ConvFN -s %1 from the batch file where the %1 parameter is a long file name and it will output the short filename equivalent...like wise the inverse, ConvFN -l %1 where %1 is the short filename and it will output the long filename equivalent.

This code was taken from pinvoke.net.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文