Eliminando la ruta y la extensión del nombre de archivo en powershell

99

Tengo una serie de cadenas que son rutas completas a los archivos. Me gustaría guardar solo el nombre del archivo, sin la extensión del archivo y la ruta principal. Entonces de esto:

c:\temp\myfile.txt

a

myfile

En realidad, no estoy iterando a través de un directorio, en cuyo caso se basenamepodría usar algo como la propiedad de powershell , sino que estoy tratando solo con cadenas.

larryq
fuente
7
muchas respuestas no tienen en cuenta la segunda parte de la pregunta. Cuando se utilizan Get-Item, Get-ChildItem o sus alias ls, dir, gi, gci, el archivo de la cadena probada debe existir . Cuando estamos comprobando una serie de cadenas y no iterando a través de un directorio , se debe asumir que esos archivos no necesitan existir en la computadora donde se ejecutará este script.
papo

Respuestas:

110

Hay un método .NET útil para eso:

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

Es mucho más fácil de lo que pensaba abordar el problema de mostrar la ruta completa, el directorio, el nombre del archivo o la extensión del archivo.

$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

otras 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)
Leonardo
fuente
25
Sería bueno si al lado de cada ejemplo en el fragmento de código superior mostrara exactamente qué texto se devolvería.
deadlydog
Ejemplo en el que no sé el nombre del archivo .csr, pero sé que existe un archivo: $csr = Get-ChildItem -Path "$($domain.FullName)/*.csr"entoncesWrite-Host "fileName: $($csr.Basename)"
Scott Pelak
46

Inspirado por una respuesta de @ walid2mi:

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

Tenga en cuenta: esto solo funciona si el archivo dado realmente existe .

CodeFox
fuente
1
Esta es la forma más fácil de obtener el nombre de archivo para un solo archivo.
marzo
6
Esto supone que el archivo existe. Eliminar una extensión de un nombre de archivo no debería depender de eso. ¿Qué sucede si está creando un archivo basado en un nombre de archivo donde el archivo no existe? La ruta es una cadena y debe tratarse como una cadena, no se supone que sea un archivo existente.
Antony Booth
29

o

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

o

"c:\temp\myfile.txt".split('\.')[-2]
walid2mi
fuente
9
El segundo ejemplo no funciona muy bien con algo como: "C: \ Downloads \ ReSharperSetup.7.0.97.60.msi" .split ('\.') [- 2]
Keith Hill
24

puedes usar la propiedad basename

PS II> ls *.ps1 | select basename
walid2mi
fuente
7
El OP dice: en realidad no estoy iterando a través de un directorio.
CB.
1
¡Muy útil para mí!
iheartcsharp
5

@Keith ,

aquí otra opción:

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]
walid2mi
fuente
4

Dada cualquier cadena de ruta arbitraria, varios métodos estáticos en el objeto System.IO.Path dan los siguientes 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 continuación se muestra el código que generó el resultado anterior.

[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 ) );

Escribir y probar el script que generó lo anterior descubrió algunas peculiaridades sobre cómo PowerShell se diferencia de C #, C, C ++, el lenguaje de script de comandos de Windows NT y casi todo lo demás con el que tengo experiencia.

David A. Gray
fuente
3

A partir de PowerShell 6, obtiene el nombre de archivo sin extensión así:

split-path c:\temp\myfile.txt -leafBase
René Nyffenegger
fuente
Esto es correcto en powershell 6. No hay LeafBase en bog standard 5.1
finlaybob
1
Gracias por la información, he actualizado la respuesta en consecuencia. ¿Qué es el pantano ?
René Nyffenegger
2
Disculpas :) de donde soy (Reino Unido), "Bog Standard" es un término del argot para algo que es completamente ordinario, una versión "vainilla".
finlaybob
2

Este script busca en una carpeta y subcarpetas y cambia el nombre de los archivos eliminando su extensión.

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

    Foreach-Object {

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

    }
usuario12386990
fuente
2

Ampliando la respuesta de René Nyffenegger, para aquellos que no tienen acceso a la versión 6.x de PowerShell, usamos Split Path, que no prueba la existencia de archivos:

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

Esto devuelve " myfile.txt ". Si sabemos que el nombre del archivo no tiene puntos, podemos dividir la cadena y tomar la primera parte:

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

o

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

Esto devuelve " myfile ". Si el nombre del archivo puede incluir puntos, para estar seguros, podríamos usar lo siguiente:

$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)

Esto devuelve " myfile.txt.config ". Aquí prefiero usar Substring () en lugar de Replace () porque la extensión precedida por un punto también podría ser parte del nombre, como en mi ejemplo. Al usar Substring, devolvemos el nombre del archivo sin la extensión solicitada.

Papa Ccompis
fuente
1
muchas gracias por esta respuesta, es muy completa y me ayudó
Sam
1

Aquí hay uno sin paréntesis

[io.fileinfo] 'c:\temp\myfile.txt' | % basename
Steven Penny
fuente
1

Esto se puede hacer dividiendo la cuerda un par de veces.

#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

Aquí está el código sin comentarios:

$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
OneOfThePetes
fuente
1
¿Por qué tan difícil?
Jaroslav Štreit
2
No funciona si el nombre del archivo contiene más de un punto, por ejemplo, MyApp.exe.config
Joe