Saya memiliki dua jalur:
fred\frog
dan
..\frag
Saya dapat menggabungkan mereka bersama di PowerShell seperti ini:
join-path 'fred\frog' '..\frag'
Itu memberi saya ini:
fred\frog\..\frag
Tapi saya tidak menginginkan itu. Saya ingin jalur yang dinormalisasi tanpa titik ganda, seperti ini:
fred\frag
Bagaimana saya bisa mendapatkannya?
powershell
path
dan-gph
sumber
sumber
Jawaban:
Anda dapat menggunakan kombinasi dari
pwd
,Join-Path
dan[System.IO.Path]::GetFullPath
untuk mendapatkan jalur yang diperluas sepenuhnya.Karena
cd
(Set-Location
) tidak mengubah proses direktori kerja saat ini, cukup meneruskan nama file relatif ke .NET API yang tidak memahami konteks PowerShell, dapat memiliki efek samping yang tidak diinginkan, seperti menyelesaikan ke jalur berdasarkan pekerjaan awal direktori (bukan lokasi Anda saat ini).Apa yang Anda lakukan adalah pertama-tama Anda memenuhi syarat untuk jalur Anda:
Join-Path (Join-Path (pwd) fred\frog) '..\frag'
Hasil ini (mengingat lokasi saya saat ini):
Dengan basis absolut, aman untuk memanggil .NET API
GetFullPath
:[System.IO.Path]::GetFullPath((Join-Path (Join-Path (pwd) fred\frog) '..\frag'))
Yang memberi Anda jalur yang sepenuhnya memenuhi syarat dan dengan yang
..
dihapus:Ini juga tidak rumit, secara pribadi, saya meremehkan solusi yang bergantung pada skrip eksternal untuk ini, ini masalah sederhana diselesaikan dengan tepat oleh
Join-Path
danpwd
(GetFullPath
hanya untuk membuatnya cantik). Jika Anda hanya ingin menyimpan bagian yang relatif saja , Anda tinggal menambahkan.Substring((pwd).Path.Trim('\').Length + 1)
dan voila!MEMPERBARUI
Terima kasih kepada @Dangph karena telah menunjukkan
C:\
case edge.sumber
cd c:\; "C:\fred\frag".Substring((pwd).Path.Length + 1)
. Itu bukan masalah besar; hanya sesuatu yang harus diperhatikan.cd c:\; "C:\fred\frag".Substring((pwd).Path.Trim('\').Length + 1)
. Ini agak lama.Anda dapat memperluas .. \ frag ke jalur lengkapnya dengan jalur penyelesaian:
Cobalah untuk menormalkan jalur menggunakan metode gabung ():
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
sumber
C:\Windows
vsC:\Windows\
jalur yang sama tetapi dua hasil yang berbeda[io.path]::Combine
dibalik. Lebih baik lagi, gunakanJoin-Path
perintah PowerShell asli :Join-Path (Resolve-Path ..\frag).Path 'fred\frog'
Perhatikan juga bahwa, setidaknya pada PowerShell v3,Resolve-Path
sekarang mendukung-Relative
sakelar untuk menyelesaikan ke jalur yang terkait dengan folder saat ini. Seperti yang disebutkan,Resolve-Path
hanya berfungsi dengan jalur yang ada, tidak seperti[IO.Path]::GetFullPath()
.Anda juga bisa menggunakan Path.GetFullPath , meskipun (seperti jawaban Dan R) ini akan memberi Anda seluruh jalur. Penggunaannya adalah sebagai berikut:
[IO.Path]::GetFullPath( "fred\frog\..\frag" )
atau lebih menariknya
[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
keduanya menghasilkan yang berikut (dengan asumsi direktori Anda saat ini adalah D: \):
Perhatikan bahwa metode ini tidak mencoba menentukan apakah fred atau frag benar-benar ada.
sumber
[System.IO.Directory]::SetCurrentDirectory(((Get-Location -PSProvider FileSystem).ProviderPath))
[IO.Path]::GetFullPath()
:, tidak seperti PowerShell asliResolve-Path
, bekerja dengan jalur yang tidak ada juga. Sisi negatifnya adalah kebutuhan untuk menyinkronkan folder kerja .NET dengan PS 'terlebih dahulu, seperti yang ditunjukkan @JasonMArcher.Join-Path
menyebabkan pengecualian jika merujuk ke drive yang tidak ada.Jawaban yang diterima sangat membantu namun tidak dengan benar 'menormalkan' jalur absolut juga. Temukan di bawah karya turunan saya yang menormalkan jalur absolut dan relatif.
function Get-AbsolutePath ($Path) { # System.IO.Path.Combine has two properties making it necesarry here: # 1) correctly deals with situations where $Path (the second term) is an absolute path # 2) correctly deals with situations where $Path (the second term) is relative # (join-path) commandlet does not have this first property $Path = [System.IO.Path]::Combine( ((pwd).Path), ($Path) ); # this piece strips out any relative path modifiers like '..' and '.' $Path = [System.IO.Path]::GetFullPath($Path); return $Path; }
sumber
[IO.Path]::GetFullPath()
tidak benar menentukan direktori untuk nama file biasa.Semua fungsi manipulasi jalur non-PowerShell (seperti yang ada di System.IO.Path) tidak akan dapat diandalkan dari PowerShell karena model penyedia PowerShell memungkinkan jalur PowerShell saat ini berbeda dari apa yang menurut Windows adalah direktori kerja proses.
Juga, seperti yang mungkin telah Anda temukan, cmdlet Resolve-Path dan Convert-Path PowerShell berguna untuk mengubah jalur relatif (yang berisi '..') ke jalur absolut berkualifikasi drive tetapi gagal jika jalur yang dirujuk tidak ada.
Cmdlet yang sangat sederhana berikut harus berfungsi untuk jalur yang tidak ada. Ini akan mengubah 'fred \ frog \ .. \ frag' menjadi 'd: \ fred \ frag' meskipun file atau folder 'fred' atau 'frag' tidak dapat ditemukan (dan drive PowerShell saat ini adalah 'd:') .
function Get-AbsolutePath { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Path ) process { $Path | ForEach-Object { $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($_) } } }
sumber
Get-AbsolutePath q:\foo\bar\..\baz
gagal meskipun itu adalah jalur yang valid. Tergantung pada definisi Anda tentang jalur yang valid. :-) FWIW, bahkan built-inTest-Path <path> -IsValid
gagal pada jalur yang di-root pada drive yang tidak ada.HKLM:\SOFTWARE
adalah jalur yang valid di PowerShell, mengacu padaSOFTWARE
kunci di kumpulan registri Mesin Lokal. Tetapi untuk mengetahui apakah itu valid, perlu untuk mencari tahu apa aturan untuk jalur registri.Library ini bagus: NDepend.Helpers.FileDirectoryPath .
EDIT: Inilah yang saya dapatkan:
[Reflection.Assembly]::LoadFrom("path\to\NDepend.Helpers.FileDirectoryPath.dll") | out-null Function NormalizePath ($path) { if (-not $path.StartsWith('.\')) # FilePathRelative requires relative paths to begin with '.' { $path = ".\$path" } if ($path -eq '.\.') # FilePathRelative can't deal with this case { $result = '.' } else { $relPath = New-Object NDepend.Helpers.FileDirectoryPath.FilePathRelative($path) $result = $relPath.Path } if ($result.StartsWith('.\')) # remove '.\'. { $result = $result.SubString(2) } $result }
Sebut saja seperti ini:
> NormalizePath "fred\frog\..\frag" fred\frag
Perhatikan bahwa cuplikan ini memerlukan jalur ke DLL. Ada trik yang dapat Anda gunakan untuk menemukan folder yang berisi skrip yang sedang dieksekusi, tetapi dalam kasus saya, saya memiliki variabel lingkungan yang dapat saya gunakan, jadi saya hanya menggunakannya.
sumber
Ini memberikan jalur lengkap:
(gci 'fred\frog\..\frag').FullName
Ini memberikan jalur relatif ke direktori saat ini:
(gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '')
Untuk beberapa alasan, mereka hanya berfungsi jika
frag
berupa file, bukandirectory
.sumber
Buat sebuah fungsi. Fungsi ini akan menormalkan jalur yang tidak ada di sistem Anda serta tidak menambahkan huruf drive.
function RemoveDotsInPath { [cmdletbinding()] Param( [Parameter(Position=0, Mandatory=$true)] [string] $PathString = '' ) $newPath = $PathString -creplace '(?<grp>[^\n\\]+\\)+(?<-grp>\.\.\\)+(?(grp)(?!))', '' return $newPath }
Ex:
$a = 'fooA\obj\BusinessLayer\..\..\bin\BusinessLayer\foo.txt' RemoveDotsInPath $a 'fooA\bin\BusinessLayer\foo.txt'
Terima kasih kepada Oliver Schadlich atas bantuannya di RegEx.
sumber
somepaththing\.\filename.txt
karena itu membuat titik tunggal ituJika jalur menyertakan kualifikasi (huruf kandar) maka jawaban x0n untuk Powershell: selesaikan jalur yang mungkin tidak ada? akan menormalkan jalur. Jika jalur tidak menyertakan kualifikasi, itu akan tetap dinormalisasi tetapi akan mengembalikan jalur yang sepenuhnya memenuhi syarat relatif ke direktori saat ini, yang mungkin bukan yang Anda inginkan.
$p = 'X:\fred\frog\..\frag' $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p) X:\fred\frag $p = '\fred\frog\..\frag' $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p) C:\fred\frag $p = 'fred\frog\..\frag' $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p) C:\Users\WileCau\fred\frag
sumber
Jika Anda perlu membuang bagian .., Anda dapat menggunakan objek System.IO.DirectoryInfo. Gunakan 'fred \ frog .. \ frag' di konstruktor. Properti FullName akan memberi Anda nama direktori yang dinormalisasi.
Satu-satunya kelemahan adalah ia akan memberi Anda seluruh jalur (misalnya c: \ test \ fred \ frag).
sumber
Bagian berguna dari komentar di sini digabungkan sedemikian rupa sehingga menyatukan jalur relatif dan absolut:
[System.IO.Directory]::SetCurrentDirectory($pwd) [IO.Path]::GetFullPath($dapath)
Beberapa contoh:
$fps = '.', 'file.txt', '.\file.txt', '..\file.txt', 'c:\somewhere\file.txt' $fps | % { [IO.Path]::GetFullPath($_) }
keluaran:
sumber
Nah, salah satu caranya adalah:
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
Tunggu, mungkin saya salah paham dengan pertanyaan itu. Dalam contoh Anda, apakah frag merupakan subfolder dari katak?
sumber