バッチファイルからコマンドライン引数の短いファイル名を取得する
-
25-09-2019 - |
質問
バッチ ファイル内の次のコマンドは期待どおりに機能しません。
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
基本的に、ファイル名を コウモリ ファイルを作成し、スクリプトにそれを短いファイル名として取得 (表示など) させますが、ファイル名と拡張子のみが取得され、ドライブやパスは取得されません。
のヘルプ情報 のために 与える %~fsI 例として挙げますが、これにはファイルだけでなく、パス全体が短いファイル名として含まれています。Sパラメータを組み合わせる方法を知っている人はいますか %~ パス全体を取得せずに?
どうもありがとう。
アップデート
別の言語での解決策を探しているのではなく、BAT コマンドが機能する必要があります。
他のものではうまくいくようなので、何らかの代替構成の問題であるかどうかを確認しています。現在、コマンド プロセッサ拡張機能が原因であるかどうかをテスト中です。
拡張機能が無効になっている場合は (当然ですが) まったく機能しないため、後続のサービス パックで修正されたバグであるという仮説を立てます (テストしたシステムは XP SP1)。今日は SP2 と SP3 をテストしています…
解決
まあ、私はちょうどそれを確認しました。私はXP SP1、SP2、SP3と同様にSP2 VMインストールからCMD.EXEでスクリプトをテストしました。これは、SP1のバージョンと、前述の誤った結果を与えたが、SP2とSP3のバージョンで正常に働いていました。だから、実際に修正されたバグです。このに走る他の誰のために、SP2 +からCMD.EXEファイルが(更新が不可能であると仮定して)問題なくSP1のインストールにドロップすることができます。
他のヒント
このフォーラムのポストを見てください。コードの次のようになります。
%~snx
s ... short
n ... name
x ... extension
私はあなたのバッチを実行して問題はありません。ホープ誰かがすぐにあなたを助けることができます。あなたがそれでありながら、しかし、ここで私はあなたがに慣れるべきだと思うの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
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
これを行うための別の方法があり、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#プロジェクトにこれを追加し、それを構築します。その後、%1パラメータが長いファイル名で、バッチファイルからConvFN -s%1呼び出し、それが出力されます短いファイル名と同等...賢明な逆のような、ConvFN -l%%1が短いファイル名である1とそれが出力されます長いファイル名を同等ます。
このコードはpinvoke.netから採取した。