Получение короткого имени аргумента командной строки из командного файла - PullRequest
2 голосов
/ 03 февраля 2010

Следующая команда в пакетном файле не работает должным образом / ожидаемая:

1003 *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 сегодня ...

Ответы [ 5 ]

2 голосов
/ 16 ноября 2011

Посмотрите на это сообщение на форуме . Код выглядит так:

%~snx
s ... short 
n ... name
x ... extension
2 голосов
/ 04 февраля 2010

Ну, я только что подтвердил это. Я протестировал скрипт с CMD.EXE из XP SP1, SP2 и SP3, а также с установкой виртуальной машины SP2. Это дало вышеупомянутые ошибочные результаты с версией SP1, но работало правильно в версиях SP2 и SP3. Так что это действительно ошибка, которая была исправлена. Для всех, кто сталкивается с этим, файл CMD.EXE из SP2 + можно без проблем поместить в установку SP1 (при условии, что обновление невозможно).

0 голосов
/ 26 июля 2011

1 - сохранить код в ShortFileName.Vbs

2- Перетащите n Удалите любую папку или файл в этот скрипт

    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
0 голосов
/ 03 февраля 2010

Есть еще один способ сделать это, скомпилировать этот код в 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();
        }
    }
}

Добавьте это в проект Console C # под названием ConvFN и соберите его. Затем вызовите ConvFN -s% 1 из пакетного файла, где параметр% 1 является длинным именем файла, и он выведет эквивалент короткого имени файла ... как и обратное, ConvFN -l% 1, где% 1 - короткое имя файла он выведет эквивалент длинного имени файла.

Этот код был взят с pinvoke.net.

0 голосов
/ 03 февраля 2010

У меня нет проблем с выполнением вашей партии.Надеюсь, что кто-то может помочь вам в ближайшее время.Но пока вы работаете над этим, вот альтернатива, сделанная с Vbscript, с которой, я думаю, вы должны ознакомиться

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

в командной строке (или вашей партии), назовите это так

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...