Göreli yoldan ve / veya dosya adından mutlak yolu çözümleme


155

Windows toplu komut dosyasında, dosya adı ve / veya göreli yol içeren bir değerden mutlak bir yol döndürmenin bir yolu var mı?

Verilen:

"..\"
"..\somefile.txt"

Toplu iş dosyasına göre mutlak yol gerekir.

Misal:

  • "somefile.txt", "C: \ Foo \" konumunda bulunur
  • "test.bat" "C: \ Foo \ Bar" içinde bulunur.
  • Kullanıcı "C: \ Foo" da bir komut penceresi açar ve Bar\test.bat ..\somefile.txt
  • Toplu iş dosyasında "C: \ Foo \ somefile.txt" %1

1
Göreli yollar hikayenin sonu değildir. NTFS bağlantılarını da göz önünde bulundurun : büyük olasılıkla realpathsağlam yol normalleştirmesi için bir analoga ihtiyacınız olacaktır .
ulidtko

Muhtemelen kesin bir yola ihtiyacınız yok! Sadece bir temel yol ekleyebilirsiniz: SET FilePath=%CD%\%1böylece böyle olabilir C:\Foo\Bar\..\..\some\other\dir\file.txt. Programlar böylesine karmaşık bir yolu anlıyor görünmektedir.
Fr0sT

Bu cevapların birçoğu karmaşık ya da sadece düz buggy - deli, ama bu aslında toplu iş yapmak oldukça kolay bir şey, aşağıdaki cevabım bir göz atın .
BrainSlugs83

Yanıtlar:


160

Toplu dosyalarda, standart C programlarında olduğu gibi, 0 bağımsız değişkeni o anda yürütülmekte olan komut dosyasının yolunu içerir. %~dp00. bağımsız değişkenin (geçerli komut dosyası olan) yalnızca yol bölümünü almak için kullanabilirsiniz - bu yol her zaman tam nitelikli bir yoldur.

Kullanarak ilk argümanınızın tam yolunu da alabilirsiniz %~f1, ancak bu geçerli çalışma dizinine göre bir yol verir, ki bu kesinlikle istediğiniz şey değildir.

Şahsen, %~dp0%~1toplu iş dosyamdaki deyimi sık sık kullanıyorum , bu da ilk argümanı yürütme toplu işleminin yoluna göre yorumlar. Yine de bir eksikliği var: ilk argüman tam olarak nitelendirilirse sefil bir şekilde başarısız olur.

Her iki akraba desteklemek gerekirse ve mutlak yolları, sen yararlanabilir Frédéric Menez çözümüyle : geçici olarak geçerli çalışma dizini değiştirin.

İşte bu tekniklerin her birini gösterecek bir örnek:

@echo off
echo %%~dp0 is "%~dp0"
echo %%0 is "%0"
echo %%~dpnx0 is "%~dpnx0"
echo %%~f1 is "%~f1"
echo %%~dp0%%~1 is "%~dp0%~1"

rem Temporarily change the current working directory, to retrieve a full path 
rem   to the first parameter
pushd .
cd %~dp0
echo batch-relative %%~f1 is "%~f1"
popd

Bunu c: \ temp \ example.bat olarak kaydederseniz ve c: \ Users \ Public as

c: \ Kullanıcılar \ Herkese Açık> \ temp \ example.bat .. \ windows

... şu çıktıyı gözlemleyeceksiniz:

%~dp0 is "C:\temp\"
%0 is "\temp\example.bat"
%~dpnx0 is "C:\temp\example.bat"
%~f1 is "C:\Users\windows"
%~dp0%~1 is "C:\temp\..\windows"
batch-relative %~f1 is "C:\Windows"

toplu iş argümanında izin verilen değiştirici kümesine ilişkin belgeleri burada bulabilirsiniz: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/call


4
Aynı şekilde işleyebilir %0ve %1benzer şekilde yapabilirsiniz : %~dpnx0tam nitelikli yol + toplu iş dosyasının kendisinin adı, %~dpnx1tam nitelikli yol + ilk argümanının adı için [bu bir dosya adı ise]. (Ama yine de komut satırında tam yol bilgisini vermezseniz, farklı bir sürücüdeki bir dosyayı nasıl adlandırırsınız?)
Kurt Pfeifle

Bu örnek @ frédéric-ménez yanıtından çok daha karmaşıktır
52'de srossross

3
Bu NTFS simgeleri üzerinde başarısız olur.
ulidtko

@KurtPfeifle d:\foo\..\bar\xyz.txthala normalleştirilebilir. Bu yaklaşımı aşağıdaki @ axel-heider'ın cevabı ile kullanmanızı öneririm (toplu bir alt program kullanarak - o zaman bunu sadece numaralı bir değişken üzerinde değil, herhangi bir değişken üzerinde yapabilirsiniz).
BrainSlugs83

@ulidtko biraz ayrıntı verebilir misiniz? Ne başarısız olur? - Ne olmasını bekliyorsun? - Orijinal klasöre çözümlemeyi mi bekliyorsunuz? (İdiyse Çünkü o , ben çağırır o bir başarısızlık - bu tür ilk etapta sembolik olmasının noktasının var ...)
BrainSlugs83

151

Bu sabah benzer bir ihtiyaçla karşılaştım: göreceli bir yolu bir Windows komut komut dosyasının içindeki mutlak bir yola nasıl dönüştürürüm.

Aşağıdaki hile yaptı:

@echo off

set REL_PATH=..\..\
set ABS_PATH=

rem // Save current directory and change to target directory
pushd %REL_PATH%

rem // Save value of CD variable (current directory)
set ABS_PATH=%CD%

rem // Restore original directory
popd

echo Relative path: %REL_PATH%
echo Maps to path: %ABS_PATH%

2
Bu GERÇEKTEN faydalıdır. Bu gibi toplu iş hileleri için iyi kaynaklar var mı?
Danny Parker

8
Önce "pushd" ve ardından "cd" olması gerektiğini düşünmeyin. Sadece "% REL_PATH% pushd" yapabilirsiniz. Bu, geçerli dizini kaydedecek ve bir seferde REL_PATH'e geçecektir.
Eddie Sullivan

1
@DannyParker Toplu tekniklerin ve örnek komut dosyalarının yararlı bir koleksiyonu robvanderwoude.com/batchfiles.php'dir . Ayrıca bkz. Stackoverflow.com/questions/245395/…
hfs

6
@EddieSullivan Eğer dizine geçmek başarısız olursa (dizin mevcut değil, izin yok ...), pushd komutu da başarısız olur ve aslında dizin yığınına bir değer itmez. Bir sonraki çağrı (ve ardışık tüm çağrılar) yanlış değer verir. Kullanmak pushd .bu sorunu önler.
SvenS

1
Bunun, dosyalar olan yollarda veya ortada bir yerde .. bulunan varolmayan yollarda çalışmadığını unutmayın. Benim için bir gösteri tıpası değildi, ama yeniden kullanılabilir bir çözüm için bir zayıflık.
Mihai Danila

97

Bu cevapların çoğu karmaşık ve süper buggy üzerinde deli gibi görünüyor, işte benim - herhangi bir ortam değişkeni üzerinde çalışıyor, hayır %CD%veya PUSHD/ POPDveya for /fsaçmalık - sadece düz eski toplu işlevler. - Dizin ve dosyanın var olması bile gerekmez.

CALL :NORMALIZEPATH "..\..\..\foo\bar.txt"
SET BLAH=%RETVAL%

ECHO "%BLAH%"

:: ========== FUNCTIONS ==========
EXIT /B

:NORMALIZEPATH
  SET RETVAL=%~f1
  EXIT /B

7
Bu gerçekten temiz, çalışan ve anlaşılır bir çözümdür.
Razvan

3
Çok özlü. Bu tekniği şimdi yaygın olarak kullanıyorum.
Paulo França Lacerda

1
Neden sadece% ~ f1 değil,% ~ dpfn1? Bu bir tür geçici çözüm mü? % ~ f1 benim için en azından Windows 7 ve Windows 10'da iyi çalışıyor.
il - ya

1
@ il - ya %~f1sadece kısadır %~dpfn1- bu yüzden kullanmaktan çekinmeyin %~f1. Format - uzun formatta ~, tırnak işareti kaldırılır, dsürücü, pyol anlamına gelir, ntek başına uzantı olmadan dosya adı olur, ancak fnuzantı ile dosya adı anlamına gelir. 1İlk bağımsız değişken anlamına gelir. - (Bu biçimin Windows 7'den önce geldiğine inanıyorum.)
BrainSlugs83

1
Ah, beni dövüyorsun! Nt4 kaynak kodundaki bir açıklamaya göre, nt4 \ private \ windows \ cmd \ clex.c dosyası (27/08/1997 tarihli), işlev MSCmdVar (), "//% ~ fi -% i öğesini tam nitelikli bir yola genişletir name "Rahatsız ettiğim için özür dilerim. Bu yanlış anlamanın en altına inebileceğimi umuyordum. Oldukça yeni bir kodu incelerken% ~ dpfn ile karşılaştım, ne yapmam gerektiğini anlamaya çalışırken tüylerimden birkaçını çektim (çok fazla kalmamışım) ve hayata nasıl yayıldığını araştırmaya başladım kişisel kan davası.
il - ya

35

Bağımsız değişkenleri başka bir toplu iş dosyasına aktarmak zorunda kalmadan (ve bağımsız değişken işleçlerini kullanmak zorunda kalmadan) şunları kullanabilirsiniz FOR /F:

FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi

burada iin %%~fi, adresinde tanımlanan değişkendir /F %%i. Örneğin. Eğer bunu değiştirirseniz /F %%a, son bölüm olurdu %%~fa.

Aynı şeyi komut isteminde (toplu iş dosyasında değil) %%yapmak için %...


Dizini değiştirmemek önemlidir, çünkü cdkomutun %CD%ortam değişkenini zorunlu olarak değiştirmemesi gerçeğine göre tarifi D:C:
sağlamlaştırır

@jez Bunun için kullanabilirsinizcd /D D:\on.other.drive
Sebastian

1
FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi..\relativePathboşluklar varsa başarısız olur
Sebastian

1
/ F bayrağını kaldırdığımda ve %% ~ dpfnI kullandığımda çalıştı. for /?İkame parametreleriyle karışıklığı önlemek için değişken adları için büyük harfler kullanılmasını öneren not
Sebastian

1
@SebastianGodelet kaldırma /F, var olmayan yollarda çalışmaz ve joker karakterleri çözer. Bunu istiyorsanız, harika, ancak işlevselliğini istiyorsanız /F, o zaman sadece tokensanahtar kelimeyi kullanmanız gerekir :FOR /F "tokens=*" %%I IN ("..\relative Path\*") DO echo absolute path: %%~fI
SvenS

15

Bu Adrien Plisson'ın cevabındaki boşlukları doldurmaya yardımcı olmak için (onu düzenler düzenlemez kaldırılması gerekir ;-):

% ~ f1 kullanarak ilk argümanınızın tam yolunu da alabilirsiniz, ancak bu geçerli yola göre bir yol verir, ki bu kesinlikle istediğiniz şey değildir.

ne yazık ki, birlikte nasıl karıştırılacağı bilmiyorum ...

Birisi de idare edebilir %0ve %1aynı şekilde:

  • %~dpnx0tam toplu sürücü + yol + adı + toplu dosyanın kendisi uzantısı için
    %~f0de yeterlidir;
  • %~dpnx1tam argüman + yol + isim + ilk argümanının genişletilmesi için [bu bir dosya adı ise]
    %~f1da yeterlidir;

%~f1ilk argümanınızı nasıl belirttiğinizden bağımsız olarak çalışır: göreli yollarla veya mutlak yollarla (adlandırma sırasında dosyanın uzantısını belirtmezseniz %1, kullansanız bile eklenmez%~dpnx1 .

Ama başka bir sürücüdeki bir dosyayı nasıl adlandırırsınız , ilk etapta komut satırında tam yol bilgisini vermeyecekseniz, ?

Ancak, %~p0 , %~n0, %~nx0ve %~x0uzantısı veya yalnızca dosya ismi uzantısı ile, (driveletter olmadan) yolu ile ilgilenen olmalıdır kullanışlı (uzantı olmadan) dosya adı, tam dosya adı gelebilir. Ama dikkat, süre %~p1ve %~n1ilk argüman yolunu veya adını bulmak için çalışacak, %~nx1ve %~x1+ ekle zaten komut satırında kullandı sürece, uzantıyı görünmez.


sorun %~dpnx1, geçerli dizine göre bağımsız değişkenin tam yolunu verirken, OP toplu iş dosyasının bulunduğu dizine göre yolu ister .
Adrien Plisson

1
@Adrien Plisson: %~dpnx11. argümanın tam yolunu verir. Hiç göreceli değil ve geçerli dir ile de ilgili değil. d, Sürücü için ise p, yolun içindir ndosya ismi sans soneki içindir x, sonek içindir 1ilk argüman içindir. - Ve Nathan'ın sorusu şuydu: "Dosya adı ve / veya göreli yol içeren bir değerden mutlak bir yol döndürmenin bir yolu var mı?"
Kurt Pfeifle

Hem mutlak hem de göreli yolların kullanımı ve kaynağı ile bir açıklama . Takdir eden!
it3xl

10

Bunun için toplu iş işlevlerini de kullanabilirsiniz:

@echo off
setlocal 

goto MAIN
::-----------------------------------------------
:: "%~f2" get abs path of %~2. 
::"%~fs2" get abs path with short names of %~2.
:setAbsPath
  setlocal
  set __absPath=%~f2
  endlocal && set %1=%__absPath%
  goto :eof
::-----------------------------------------------

:MAIN
call :setAbsPath ABS_PATH ..\
echo %ABS_PATH%

endlocal

9

BrainSlugs83'ün mükemmel çözümünde küçük bir gelişme . Aramadaki çıkış ortamı değişkeninin adlandırılmasına izin vermek için genelleştirilmiştir.

@echo off
setlocal EnableDelayedExpansion

rem Example input value.
set RelativePath=doc\build

rem Resolve path.
call :ResolvePath AbsolutePath %RelativePath%

rem Output result.
echo %AbsolutePath%

rem End.
exit /b

rem === Functions ===

rem Resolve path to absolute.
rem Param 1: Name of output variable.
rem Param 2: Path to resolve.
rem Return: Resolved absolute path.
:ResolvePath
    set %1=%~dpfn2
    exit /b

C:\projectÇıktıdan çalıştır :

C:\project\doc\build

4

Bu soruna çok fazla çözüm görmedim. Bazı çözümler CD kullanarak dizin geçişini kullanırken, diğerleri toplu işlevleri kullanır. Kişisel tercihim toplu işlevler ve özellikle MakeAbsolute içindi tarafından sağlanan işlevi olmuştur.

Bu işlevin bazı gerçek faydaları vardır, öncelikle geçerli çalışma dizininizi değiştirmez ve ikinci olarak değerlendirilen yolların var olması bile gerekmez. Burada işlevi nasıl kullanacağınıza ilişkin bazı yararlı ipuçları bulabilirsiniz .

İşte örnek bir komut dosyası ve çıktıları:

@echo off

set scriptpath=%~dp0
set siblingfile=sibling.bat
set siblingfolder=sibling\
set fnwsfolder=folder name with spaces\
set descendantfolder=sibling\descendant\
set ancestorfolder=..\..\
set cousinfolder=..\uncle\cousin

call:MakeAbsolute siblingfile      "%scriptpath%"
call:MakeAbsolute siblingfolder    "%scriptpath%"
call:MakeAbsolute fnwsfolder       "%scriptpath%"
call:MakeAbsolute descendantfolder "%scriptpath%"
call:MakeAbsolute ancestorfolder   "%scriptpath%"
call:MakeAbsolute cousinfolder     "%scriptpath%"

echo scriptpath:       %scriptpath%
echo siblingfile:      %siblingfile%
echo siblingfolder:    %siblingfolder%
echo fnwsfolder:       %fnwsfolder%
echo descendantfolder: %descendantfolder%
echo ancestorfolder:   %ancestorfolder%
echo cousinfolder:     %cousinfolder%
GOTO:EOF

::----------------------------------------------------------------------------------
:: Function declarations
:: Handy to read http://www.dostips.com/DtTutoFunctions.php for how dos functions
:: work.
::----------------------------------------------------------------------------------
:MakeAbsolute file base -- makes a file name absolute considering a base path
::                      -- file [in,out] - variable with file name to be converted, or file name itself for result in stdout
::                      -- base [in,opt] - base path, leave blank for current directory
:$created 20060101 :$changed 20080219 :$categories Path
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set "src=%~1"
if defined %1 set "src=!%~1!"
set "bas=%~2"
if not defined bas set "bas=%cd%"
for /f "tokens=*" %%a in ("%bas%.\%src%") do set "src=%%~fa"
( ENDLOCAL & REM RETURN VALUES
    IF defined %1 (SET %~1=%src%) ELSE ECHO.%src%
)
EXIT /b

Ve çıktı:

C:\Users\dayneo\Documents>myscript
scriptpath:       C:\Users\dayneo\Documents\
siblingfile:      C:\Users\dayneo\Documents\sibling.bat
siblingfolder:    C:\Users\dayneo\Documents\sibling\
fnwsfolder:       C:\Users\dayneo\Documents\folder name with spaces\
descendantfolder: C:\Users\dayneo\Documents\sibling\descendant\
ancestorfolder:   C:\Users\
cousinfolder:     C:\Users\dayneo\uncle\cousin

Umarım bu yardımcı olur ... Kesinlikle bana yardımcı oldu :) PS DosTips için tekrar teşekkürler! Harikasın!


teşekkürler @ulidtko. Daha önce sembolik bağlantıları denemedim.
dayneo

2

Bunları birleştirebilirsiniz.

SET ABS_PATH=%~dp0 
SET REL_PATH=..\SomeFile.txt
SET COMBINED_PATH=%ABS_PATH%%REL_PATH%

yolunuzun ortasında \ .. \ ile garip görünüyor ama çalışıyor. Çılgınca bir şey yapmaya gerek yok :)


Bu sadece işe yarıyor. Daha da basitleştirilebilirecho %~dp0..\SomeFile.txt
cowlinator

1

Örneğin, Bar \ test.bat dosyasında, DIR / B / S .. \ somefile.txt tam yolu döndürür.


Bu kötü bir fikir değil ... Bir FOR ile DIR sonucunun üzerinden geçmeli ve sadece ilk sonucu mu almalıyım?
Nathan Taylor

Birden fazla dosya ile ilgili sorunu düşündüm. Katların bir sorun olup olmadığını belirtmedin, ben de onunla gittim. Bir FOR döngüsüne gelince, bir for döngüsüne "../" beslemede sorun yaşıyorum, ama ymmv. DIR komutuna devam edemiyorsanız, çıktıyı bir dosyaya yönlendirebilir ve bu dosya üzerinde döngü yapabilirsiniz. Yolu çıkarmanın 'standart' yolunun kötü olduğunu söylemiyorum, sadece benimkinin istediğinden daha fazlasını yaptığını düşündüm. Her iki çözüm de bir şey yapar ve her ikisinin de kendi sorunları vardır.
George Sisco

Oh ... ve, DIR'de başarılı bir şekilde döngü yaparsanız, bir dosyaya yeniden yönlendirmenin üzerine yazabilir ve son sonucu alabilirsiniz. Siparişi sizin için kabul edilebilir bir şekilde tersine çevirirseniz, sadece ilk sonucu alabilirsiniz. Dosyada döngü yapmanız gerekiyorsa, en son konumda olacak ilk sonucu elde etmek için sırası ters çevirmek de yardımcı olabilir. Bunu önermemin nedeni, aslında onlarla uğraşmak yerine birçok şeyi almak ve atmak daha kolay olabilir. Düşünme tarzımın sizin için anlamlı olup olmadığını bilmiyorum. Sadece bir fikir olarak oraya koyuyorum.
George Sisco

Bir klasörün yolunu normalleştirmeniz gerekiyorsa, şu çözümü öneririm: stackoverflow.com/questions/48764076/…
uceumern

0

PowerShell bu günlerde oldukça yaygındır, bu yüzden hemen hemen her şey için işlevleri olduğundan C #'yi çağırmanın hızlı bir yolu olarak kullanırım:

@echo off
set pathToResolve=%~dp0\..\SomeFile.txt
for /f "delims=" %%a in ('powershell -Command "[System.IO.Path]::GetFullPath( '%projectDirMc%' )"') do @set resolvedPath=%%a

echo Resolved path: %resolvedPath%

Biraz yavaş, ancak gerçek bir komut dosyası diline başvurmadan elde edilen işlevselliği yenmek zor.


0

stijn'in çözümü aşağıdaki alt klasörler ile çalışır C:\Program Files (86)\,

@echo off
set projectDirMc=test.txt

for /f "delims=" %%a in ('powershell -Command "[System.IO.Path]::GetFullPath( '%projectDirMc%' )"') do @set resolvedPath=%%a

echo full path:    %resolvedPath%

0

Dosyalar Diğer tüm cevapları görün

Dizinler

İle ..senin göreli yol olma ve varsayarak Şu anda bulunduğunuz D:\Projects\EditorProject:

cd .. & cd & cd EditorProject (göreceli yol)

mutlak yol döndürür örn.

D:\Projects


0
SET CD=%~DP0

SET REL_PATH=%CD%..\..\build\

call :ABSOLUTE_PATH    ABS_PATH   %REL_PATH%

ECHO %REL_PATH%

ECHO %ABS_PATH%

pause

exit /b

:ABSOLUTE_PATH

SET %1=%~f2

exit /b
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.