138

Có cách nào trong tập lệnh bó Windows để trả về một đường dẫn tuyệt đối từ một giá trị chứa tên tệp và / hoặc đường dẫn tương đối không?

Được:

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

Tôi cần đường dẫn tuyệt đối liên quan đến tệp bó.

Thí dụ:

  • "somefile.txt" nằm trong "C: \ Foo \"
  • "test.bat" nằm trong "C: \ Foo \ Bar".
  • Người dùng mở một cửa sổ lệnh trong "C: \ Foo" và gọi Bar\test.bat ..\somefile.txt
  • Trong tệp bó "C: \ Foo \ somefile.txt" sẽ được lấy từ %1
|
  • 1

    Con đường tương đối không phải là kết thúc của câu chuyện. Cũng xem xét các liên kết tượng trưng NTFS : rất có thể bạn cũng sẽ cần một tương tự realpathđể chuẩn hóa đường dẫn mạnh mẽ.

    – Vũ Thiên Duyên 14:03:03 10/12/2014
  • Có lẽ bạn không cần một con đường chính xác nào cả! Bạn chỉ có thể thêm một đường dẫn cơ sở: SET FilePath=%CD%\%1để nó có thể như thế C:\Foo\Bar\..\..\some\other\dir\file.txt. Các chương trình dường như hiểu một con đường phức tạp như vậy.

    – Võ Hoài Vỹ 14:00:13 19/06/2015
  • Rất nhiều câu trả lời là điên rồ vì phức tạp, hoặc chỉ là lỗi đơn giản - nhưng, đây thực sự là một điều khá dễ thực hiện theo lô, hãy xem câu trả lời của tôi dưới đây .

    – Hoàng Thành Ðệ 20:24:42 03/07/2016
148

Trong các tệp bó, như trong các chương trình C tiêu chuẩn, đối số 0 chứa đường dẫn đến tập lệnh hiện đang thực thi. Bạn có thể sử dụng %~dp0để chỉ lấy phần đường dẫn của đối số 0 (là tập lệnh hiện tại) - đường dẫn này luôn là đường dẫn đủ điều kiện.

Bạn cũng có thể có được đường dẫn đủ điều kiện của đối số đầu tiên bằng cách sử dụng %~f1, nhưng điều này đưa ra một đường dẫn theo thư mục làm việc hiện tại, đây rõ ràng không phải là điều bạn muốn.

Cá nhân, tôi thường sử dụng %~dp0%~1thành ngữ trong tệp bó của mình, nó diễn giải đối số đầu tiên liên quan đến đường dẫn của lô thực thi. Mặc dù vậy, nó có một thiếu sót: nó thất bại thảm hại nếu đối số đầu tiên đủ điều kiện.

Nếu bạn cần hỗ trợ cả hai đường dẫn tương đối tuyệt đối, bạn có thể sử dụng giải pháp của Frédéric Ménez : tạm thời thay đổi thư mục làm việc hiện tại.

Đây là một ví dụ sẽ chứng minh từng kỹ thuật sau:

@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

Nếu bạn lưu cái này dưới dạng c: \ temp \ example.bat và chạy nó từ c: \ Users \ Public dưới dạng

c: \ Users \ Public> \ temp \ example.bat .. \ windows

... bạn sẽ quan sát đầu ra sau:

%~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"
|
  • 1

    Bạn có thể xử lý %0%1tương tự: %~dpnx0đối với đường dẫn đủ điều kiện + tên của chính tệp đó, %~dpnx1đối với đường dẫn đủ điều kiện + tên của đối số đầu tiên [nếu đó hoàn toàn là tên tệp]. (Nhưng làm thế nào trên trái đất bạn sẽ đặt tên một tệp trên một ổ đĩa khác nếu bạn sẽ không cung cấp thông tin đường dẫn đầy đủ đó trên dòng lệnh?)

    – Ngô Huy Kiên 19:45:02 13/08/2010
  • 1

    Ví dụ này phức tạp hơn nhiều so với câu trả lời @ frédéric-ménez

    – Hoàng Mỹ Lợi 17:52:47 05/11/2014
  • 1

    Điều này không thành công trên symlink NTFS.

    – Đỗ Quang Vũ 14:00:47 10/12/2014
  • 1

    @KurtPfeifle d:\foo\..\bar\xyz.txtvẫn có thể được chuẩn hóa. Tôi khuyên bạn nên sử dụng phương pháp này với câu trả lời của @ axel-heider bên dưới (sử dụng chương trình con theo đợt - sau đó bạn có thể thực hiện trên bất kỳ biến nào, không chỉ là biến được đánh số).

    – Hồ Chí Dũng 02:04:16 29/10/2015
  • 1

    @ulidtko bạn có thể giải thích? Cái gì thất bại? - Bạn đang mong đợi điều gì xảy ra? - Bạn đang mong đợi để giải quyết thư mục gốc? (Bởi vì nếu nó đã làm điều đó , tôi sẽ gọi đó là một thất bại - đó là điểm có điểm liên kết ở vị trí đầu tiên ...)

    – Đặng An Gia 02:11:39 29/10/2015
135

Tôi đã gặp một nhu cầu tương tự sáng nay: làm thế nào để chuyển đổi một đường dẫn tương đối thành một đường dẫn tuyệt đối bên trong một tập lệnh của Windows.

Sau đây đã thực hiện các mẹo:

@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%
|
  • 1

    Điều này thực sự hữu ích. Có bất kỳ tài nguyên tốt cho các thủ thuật tập tin hàng loạt như thế này?

    – Tạ Diệu Ái 15:25:24 17/02/2012
  • 1

    Đừng nghĩ rằng cần phải có "đẩy" theo sau là "cd". Bạn chỉ có thể thực hiện "đẩy% REL_PATH%". Điều đó sẽ lưu thư mục hiện tại và chuyển sang REL_PATH trong một lần.

    – Tạ Hoàng Ngọc 14:15:44 27/09/2012
  • 1

    @DannyParker Một bộ sưu tập hữu ích các kỹ thuật Batch và các kịch bản ví dụ là robvanderwoude.com/batchfiles.php . Xem thêm stackoverflow.com/questions/245395/

    – Lý Gia Ðạo 09:27:03 31/10/2012
  • 1

    @EddieSullivan Nếu thay đổi thư mục không thành công (thư mục không tồn tại, không có quyền ...), lệnh Pushd cũng thất bại và sẽ không thực sự đẩy một giá trị lên ngăn xếp thư mục. Cuộc gọi tiếp theo (và tất cả các cuộc gọi liên tiếp) đến popd sẽ bật giá trị sai. Sử dụng pushd .ngăn chặn vấn đề này.

    – Võ Ban Mai 15:48:47 13/02/2013
  • 1

    Lưu ý rằng điều này sẽ không hoạt động trên các đường dẫn là tệp hoặc trên các đường dẫn không tồn tại nơi có một .. ở đâu đó ở giữa. Nó không phải là một điểm dừng chương trình đối với tôi, nhưng nó là một điểm yếu của một giải pháp tái sử dụng.

    – Huỳnh Thúy Hiền 22:55:23 05/06/2013
67

Hầu hết các câu trả lời này có vẻ điên rồ vì lỗi phức tạp và siêu lỗi, đây là của tôi - nó hoạt động trên bất kỳ biến môi trường nào, không %CD%hoặc PUSHD/POPD hoặc for /fvô nghĩa - chỉ là các hàm lô cũ đơn giản. - Thư mục & tập tin thậm chí không tồn tại.

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~dpfn1
  EXIT /B
|
35

Không cần phải có một tệp bó khác để truyền đối số cho (và sử dụng các toán tử đối số), bạn có thể sử dụng FOR /F:

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

trong đó iin %%~filà biến được định nghĩa tại /F %%i. ví dụ. nếu bạn đổi nó thành/F %%a phần cuối cùng sẽ là %%~fa.

Để làm điều tương tự ngay tại dấu nhắc lệnh (chứ không phải trong tệp bó) thay thế %%bằng %...

|
  • 1

    +1 Giải pháp đẹp mà không yêu cầu thay đổi thư mục.

    – Hoàng Cát Uy 16:47:21 04/06/2012
  • 1

    Không thay đổi thư mục rất quan trọng, bởi vì nó làm cho công thức trở nên mạnh mẽ với thực tế là cdlệnh không nhất thiết phải thay đổi %CD%biến môi trường (ví dụ: nếu bạn đang lái xe D:và đường dẫn đích của bạn được bật C:)

    – Dương Phương Hoa 18:59:46 20/11/2015
  • 1

    @jez Cho rằng bạn có thể sử dụngcd /D D:\on.other.drive

    – Ngô Hoàng Bảo 03:42:01 21/03/2016
  • 1

    Nó hoạt động khi tôi xóa cờ / F và sử dụng %% ~ dpfnI. Lưu ý rằng for /?đề xuất sử dụng chữ in hoa cho tên biến, để tránh nhầm lẫn với các tham số thay thế

    – Đỗ Hồng Tâm 09:00:45 21/03/2016
  • 1

    Loại bỏ @SebastianGodelet /Fsẽ không hoạt động trên các đường dẫn không tồn tại và nó sẽ giải quyết các ký tự đại diện. Nếu bạn muốn điều đó, thật tuyệt, nhưng nếu bạn muốn chức năng của /F, thì bạn chỉ cần sử dụng tokenstừ khóa:FOR /F "tokens=*" %%I IN ("..\relative Path\*") DO echo absolute path: %%~fI

    – Lý Bích Ngà 11:34:50 14/12/2016
15

Điều này là để giúp lấp đầy những khoảng trống trong câu trả lời của Adrien Plisson (cần được nâng cấp ngay khi anh ta chỉnh sửa nó ;-):

bạn cũng có thể nhận được đường dẫn đủ điều kiện của đối số đầu tiên của mình bằng cách sử dụng% ~ f1, nhưng điều này đưa ra một đường dẫn theo đường dẫn hiện tại, đây rõ ràng không phải là điều bạn muốn.

thật không may, tôi không biết làm thế nào để trộn cả 2 lại với nhau ...

Người ta có thể xử lý %0%1tương tự:

  • %~dpnx0 cho ổ đĩa đủ điều kiện + đường dẫn + tên + phần mở rộng của chính tập tin,
    %~f0 cũng đủ;
  • %~dpnx1đối với ổ đĩa đủ điều kiện + đường dẫn + tên + phần mở rộng của đối số đầu tiên [nếu đó hoàn toàn là tên tệp],
    %~f1cũng đủ;

%~f1sẽ hoạt động độc lập với cách bạn đã chỉ định đối số đầu tiên của mình: với các đường dẫn tương đối hoặc với các đường dẫn tuyệt đối (nếu bạn không chỉ định phần mở rộng của tệp khi đặt tên %1, nó sẽ không được thêm vào, ngay cả khi bạn sử dụng%~dpnx1 - tuy nhiên.

Nhưng làm thế nào trên trái đất bạn sẽ đặt tên một tệp trên một ổ đĩa khác nếu bạn sẽ không cung cấp thông tin đường dẫn đầy đủ đó trên dòng lệnh ở vị trí đầu tiên?

Tuy nhiên, %~p0, %~n0, %~nx0%~x0có thể có ích, bạn nên quan tâm đến con đường (không có tên ổ đĩa), tên tập tin (không có phần mở rộng), tên tập tin đầy đủ với phần mở rộng hoặc chỉ phần mở rộng tên tập tin của. Nhưng lưu ý, trong khi %~p1%~n1sẽ làm việc để tìm ra đường dẫn hoặc tên của đối số đầu tiên %~nx1%~x1sẽ không thêm + hiển thị phần mở rộng, trừ khi bạn đã sử dụng nó trên dòng lệnh.

|
  • 1

    vấn đề với %~dpnx1là nó cung cấp đường dẫn đủ điều kiện của đối số so với thư mục hiện tại , trong khi OP muốn đường dẫn liên quan đến thư mục chứa tệp bó .

    – Trần Ðức Phong 08:56:01 17/08/2010
  • 1

    @Adrien Plisson: %~dpnx1đưa ra đường dẫn đầy đủ của đối số thứ nhất. Không liên quan gì cả, và cũng không liên quan đến thư mục hiện tại. Cái dlà cho ổ đĩa, cái plà cho đường dẫn, cái ntên là hậu tố sans hậu tố, cái xlà hậu tố, cái 1là cho đối số đầu tiên. - Và câu hỏi của Nathan là: "Có cách nào để trả về một đường dẫn tuyệt đối từ một giá trị chứa tên tệp và / hoặc đường dẫn tương đối không?"

    – Trịnh Tố Nhi 09:38:38 17/08/2010
  • 1

    Cả hai, sử dụng đường dẫn tuyệt đối và tương đối nguồn với một mô tả . Đánh giá cao!

    – Tạ Hoài Thu 11:54:07 12/02/2018
9

Bạn cũng có thể sử dụng các hàm bó cho việc này:

@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
|
6

Cải thiện nhỏ cho giải pháp tuyệt vời của BrainSlugs83 . Tổng quát hóa để cho phép đặt tên biến môi trường đầu ra trong cuộc gọi.

@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

Nếu chạy từ C:\projectđầu ra là:

C:\project\doc\build
|
4

Tôi chưa thấy nhiều giải pháp cho vấn đề này. Một số giải pháp sử dụng truyền tải thư mục bằng CD và các giải pháp khác sử dụng các hàm bó. Sở thích cá nhân của tôi là dành cho các chức năng hàng loạt và đặc biệt, MakeAbsolute chức năng theo quy định của DosTips.

Hàm này có một số lợi ích thực sự, chủ yếu là nó không thay đổi thư mục làm việc hiện tại của bạn và thứ hai là các đường dẫn được đánh giá thậm chí không phải tồn tại. Bạn cũng có thể tìm thấy một số lời khuyên hữu ích về cách sử dụng chức năng ở đây .

Đây là một kịch bản ví dụ và kết quả đầu ra của nó:

@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

Và đầu ra:

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

Tôi hy vọng điều này sẽ giúp ... Nó chắc chắn đã giúp tôi :) PS Một lần nữa xin cảm ơn DosTips! Bạn đá!

|
1

Bạn chỉ có thể nối chúng.

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

nó trông có vẻ kỳ lạ với \ .. \ ở giữa đường dẫn của bạn nhưng nó hoạt động. Không cần làm gì điên cả :)

|
1

Trong ví dụ của bạn, từ Bar \ test.bat, DIR / B / S .. \ somefile.txt sẽ trả về đường dẫn đầy đủ.

|
  • 1

    Đó không phải là một ý tưởng tồi ... tôi có nên lặp lại kết quả của TRỰC TIẾP bằng FOR và chỉ lấy kết quả đầu tiên không?

    – Dương Hồng Ngọc 23:10:50 29/10/2009
  • 1

    Tôi nghĩ về vấn đề với nhiều tập tin. Bạn đã không xác định liệu bội số có phải là một vấn đề hay không, vì vậy tôi đã giải quyết nó. Đối với vòng lặp FOR, tôi gặp khó khăn khi cho "../" vào vòng lặp for, nhưng ymmv. Nếu bạn không thể thực hiện được bằng lệnh DIR, bạn có thể chuyển hướng đầu ra sang một tệp và lặp qua đó. Tôi không nói rằng cách trích xuất 'tiêu chuẩn' là không tốt, chỉ là tôi nghĩ rằng tôi đã làm nhiều hơn những gì bạn yêu cầu. Cả hai giải pháp đều làm "một cái gì đó" và cả hai đều có vấn đề riêng.

    – Hoàng Trọng Tấn 14:02:00 30/10/2009
  • 1

    Oh..và, nếu bạn lặp qua DIR thành công, bạn có thể ghi đè chuyển hướng vào một tệp và nhận kết quả cuối cùng. Nếu bạn đảo ngược thứ tự theo cách có thể chấp nhận với bạn, bạn có thể nhận được kết quả đầu tiên. Nếu bạn phải lặp qua tệp, đảo ngược thứ tự để đạt được kết quả đầu tiên ở vị trí cuối cùng cũng có thể giúp ích. Lý do tôi đề nghị là có thể dễ dàng lấy và loại bỏ nhiều thứ hơn là thực sự giải quyết chúng. Tôi không biết cách suy nghĩ của tôi có ý nghĩa với bạn. Chỉ cần đặt nó ra như là một ý tưởng.

    – Tạ Yến Phượng 14:09:57 30/10/2009
  • 1

    Nếu bạn cần bình thường hóa một đường dẫn đến một thư mục, tôi đề xuất giải pháp này: stackoverflow.com/questions/48764076/ trên

    – Tạ Hải Thụy 11:41:50 14/12/2018
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
|
0

Các tập tin Xem tất cả các câu trả lời khác

Thư mục

Với ..đường dẫn tương đối của bạn và giả sử bạn hiện đang ởD:\Projects\EditorProject :

cd .. & cd & cd EditorProject (đường dẫn tương đối)

trả về đường dẫn tuyệt đối, vd

D:\Projects

|
0

giải pháp của stijn hoạt động với các thư mục con bên dưới 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

PowerShell khá phổ biến hiện nay vì vậy tôi thường sử dụng nó như một cách nhanh chóng để gọi C # vì nó có chức năng cho mọi thứ khá nhiều:

@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%

Hơi chậm một chút, nhưng chức năng thu được rất khó để đánh bại trừ khi không dùng đến ngôn ngữ kịch bản thực tế.

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.