Removendo caminho e extensão do nome de arquivo no PowerShell


99

Tenho uma série de strings que são caminhos completos para arquivos. Gostaria de salvar apenas o nome do arquivo, sem a extensão do arquivo e o caminho inicial. Então, a partir disso:

c:\temp\myfile.txt

para

myfile

Na verdade, não estou iterando por meio de um diretório, caso em que algo como a basenamepropriedade do powershell poderia ser usado, mas estou lidando apenas com strings.


7
muitas respostas não levam em consideração a segunda parte da pergunta. Quando Get-Item, Get-ChildItem ou seus aliases ls, dir, gi, gci são usados, o arquivo da string testada deve existir . Quando estamos verificando uma série de strings e não iterando em um diretório , devemos assumir que esses arquivos não precisam existir no computador onde este script será executado.
papo

Respostas:


110

Existe um método .NET útil para isso:

C:\PS> [io.path]::GetFileNameWithoutExtension("c:\temp\myfile.txt")
myfile

93

Muito mais fácil do que pensei resolver o problema de exibir o caminho completo, diretório, nome do arquivo ou extensão do arquivo.

$PSCommandPath
(Get-Item $PSCommandPath ).Extension
(Get-Item $PSCommandPath ).Basename
(Get-Item $PSCommandPath ).Name
(Get-Item $PSCommandPath ).DirectoryName
(Get-Item $PSCommandPath ).FullName
$ConfigINI = (Get-Item $PSCommandPath ).DirectoryName+"\"+(Get-Item $PSCommandPath ).BaseName+".ini"
$ConfigINI

outras formas:

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
split-path -parent $PSCommandPath
Split-Path $script:MyInvocation.MyCommand.Path
split-path -parent $MyInvocation.MyCommand.Definition
[io.path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)

25
Seria bom se ao lado de cada exemplo no trecho de código superior você mostrasse exatamente que texto seria retornado.
deadlydog

Exemplo em que não sei o nome do arquivo .csr, mas sei que existe um arquivo: $csr = Get-ChildItem -Path "$($domain.FullName)/*.csr"entãoWrite-Host "fileName: $($csr.Basename)"
Scott Pelak

46

Inspirado por uma resposta de @ walid2mi:

(Get-Item 'c:\temp\myfile.txt').Basename

Observação: isso só funciona se o arquivo fornecido realmente existir .


1
Esta é a maneira mais fácil de obter o nome do arquivo para um único arquivo.
março

6
Isso pressupõe que o arquivo existe. Remover uma extensão de um nome de arquivo não deve depender disso. E se você estiver criando um arquivo baseado em um nome de arquivo onde o arquivo não existe? O caminho é uma string e deve ser tratado como uma string, não sendo considerado um arquivo existente.
Antony Booth

29

ou

([io.fileinfo]"c:\temp\myfile.txt").basename

ou

"c:\temp\myfile.txt".split('\.')[-2]

9
O segundo exemplo não funciona muito bem com algo como - "C: \ Downloads \ ReSharperSetup.7.0.97.60.msi" .split ('\.') [- 2]
Keith Hill

24

você pode usar a propriedade de nome de base

PS II> ls *.ps1 | select basename

7
O OP diz: Na verdade, não estou iterando por meio de um diretório.
CB.

1
Muito útil para mim!
iheartcsharp

5

@Keith ,

aqui outra opção:

PS II> $f="C:\Downloads\ReSharperSetup.7.0.97.60.msi"

PS II> $f.split('\')[-1] -replace '\.\w+$'

PS II> $f.Substring(0,$f.LastIndexOf('.')).split('\')[-1]

4

Dada qualquer string de caminho arbitrário, vários métodos estáticos no objeto System.IO.Path fornecem os seguintes resultados.

strTestPath = C: \ Users \ DAG \ Documents \ Articles_2018 \ NTFS_File_Times_in_CMD \ PathStringInfo.ps1
GetDirectoryName = C: \ Users \ DAG \ Documents \ Articles_2018 \ NTFS_File_Times_in_CMD
GetFileName = PathStringInfo.ps1
GetExtension = .ps1
GetFileNameWithoutExtension = PathStringInfo

A seguir está o código que gerou a saída acima.

[console]::Writeline( "strTestPath                 = {0}{1}" ,
                      $strTestPath , [Environment]::NewLine );
[console]::Writeline( "GetDirectoryName            = {0}" ,
                      [IO.Path]::GetDirectoryName( $strTestPath ) );
[console]::Writeline( "GetFileName                 = {0}" ,
                      [IO.Path]::GetFileName( $strTestPath ) );
[console]::Writeline( "GetExtension                = {0}" ,
                      [IO.Path]::GetExtension( $strTestPath ) );
[console]::Writeline( "GetFileNameWithoutExtension = {0}" ,
                      [IO.Path]::GetFileNameWithoutExtension( $strTestPath ) );

Escrever e testar o script que gerou o acima revelou algumas peculiaridades sobre como o PowerShell difere de C #, C, C ++, a linguagem de script de comando do Windows NT e quase tudo o mais com o qual tenho alguma experiência.


3

A partir do PowerShell 6, você obtém o nome do arquivo sem extensão, assim:

split-path c:\temp\myfile.txt -leafBase

Isso está correto no PowerShell 6. Não há LeafBase no padrão bog 5.1
finlaybob 01 de

1
Obrigado pela informação, eu atualizei a resposta em conformidade. O que é pântano ?
René Nyffenegger

2
Desculpas :) de onde eu sou (Reino Unido), "Bog Standard" é uma gíria para algo que é completamente comum, uma versão "vanilla".
finlaybob

2

Este script pesquisa em uma pasta e subpastas e renomeia arquivos removendo sua extensão

    Get-ChildItem -Path "C:/" -Recurse -Filter *.wctc |

    Foreach-Object {

      rename-item $_.fullname -newname $_.basename

    }

2

Expandindo a resposta de René Nyffenegger, para aqueles que não têm acesso ao PowerShell versão 6.x, usamos Split Path, que não testa a existência do arquivo:

Split-Path "C:\Folder\SubFolder\myfile.txt" -Leaf

Isso retorna " myfile.txt ". Se soubermos que o nome do arquivo não contém pontos, podemos dividir a string e pegar a primeira parte:

(Split-Path "C:\Folder\SubFolder\myfile.txt" -Leaf).Split('.') | Select -First 1

ou

(Split-Path "C:\Folder\SubFolder\myfile.txt" -Leaf).Split('.')[0]

Isso retorna " myfile ". Se o nome do arquivo incluir pontos, para ser seguro, poderíamos usar o seguinte:

$FileName = Split-Path "C:\Folder\SubFolder\myfile.txt.config.txt" -Leaf
$Extension = $FileName.Split('.') | Select -Last 1
$FileNameWoExt = $FileName.Substring(0, $FileName.Length - $Extension.Length - 1)

Isso retorna " myfile.txt.config ". Aqui, prefiro usar Substring () em vez de Replace () porque a extensão precedida por um ponto também pode fazer parte do nome, como no meu exemplo. Ao usar Substring, retornamos o nome do arquivo sem a extensão conforme solicitado.


1
muito obrigado por esta resposta, é muito completa e me ajudou
Sam

1

Aqui está um sem parênteses

[io.fileinfo] 'c:\temp\myfile.txt' | % basename

1

Isso pode ser feito dividindo a string algumas vezes.

#Path
$Link = "http://some.url/some/path/file.name"

#Split path on "/"
#Results of split will look like this : 
# http:
#
# some.url
# some
# path
# file.name
$Split = $Link.Split("/")

#Count how many Split strings there are
#There are 6 strings that have been split in my example
$SplitCount = $Split.Count

#Select the last string
#Result of this selection : 
# file.name
$FilenameWithExtension = $Split[$SplitCount -1]

#Split filename on "."
#Result of this split : 
# file
# name
$FilenameWithExtensionSplit = $FilenameWithExtension.Split(".")

#Select the first half
#Result of this selection : 
# file
$FilenameWithoutExtension = $FilenameWithExtensionSplit[0]

#The filename without extension is in this variable now
# file
$FilenameWithoutExtension

Aqui está o código sem comentários:

$Link = "http://some.url/some/path/file.name"
$Split = $Link.Split("/")
$SplitCount = $Split.Count
$FilenameWithExtension = $Split[$SplitCount -1]
$FilenameWithExtensionSplit = $FilenameWithExtension.Split(".")
$FilenameWithoutExtension = $FilenameWithExtensionSplit[0]
$FilenameWithoutExtension

1
Por que maneira tão difícil?
Jaroslav Štreit

2
Não funciona se o nome do arquivo contém mais de um ponto, por exemplo, MyApp.exe.config
Joe,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.