Viernes divertido: edición de la consola PowerShell
El otro día leí un interesante artículo en el blog de Adam Bertram sobre edición de archivos con un editor de texto en PowerShell. Naturalmente, las ruedas de PowerShell en mi cabeza comenzaron a girar. Si bien algunas de las opciones del artículo me intrigaron, de hecho instalé el Micro editor para jugar, me di cuenta de que ya tenía instalado mi editor de texto de consola favorito. El artículo menciona la instalación del editor Nano para Windows. Pero tengo una instalación WSL de Ubuntu. Ya tengo el nano editor. Para ser justos, instalé Nano para Windows pero es lo suficientemente diferente de la versión de Linux como para molestarme. ¿Por qué no facilitar el uso de lo que ya tengo en mi consola PowerShell? Divirtámonos un poco y tal vez aprendamos algo nuevo.
Comandos WSL
Si tiene instalada una distribución de Linux, puede ejecutar comandos nativos de Linux desde el símbolo del sistema de PowerShell.
Normalmente, estos comandos se ejecutan en un shell de Linux, pero obtengo el resultado en mi consola PowerShell. De todos modos, puedo iniciar fácilmente el editor nano directamente desde mi indicador de PowerShell.
wsl nanoConvertir rutas
Pero aquí es donde la cosa se pone complicada. Quiero poder iniciar el nano editor y abrir un archivo de texto desde Windows. En Linux, puedo ejecutar un comando como este:
nano /home/jeff/file.txt
Si intento algo como esto desde mi mensaje de PowerShell:
wsl nano c:\work\fun.ps1El nano editor se abrirá pero creo que estoy creando un archivo nuevo. Esto se debe a que nano realmente se ejecuta en la distribución de Ubuntu, no en mi mensaje de PowerShell. Afortunadamente, todas mis unidades locales se montan automáticamente en WSL. Si convierto la ruta en mi cabeza, esto funcionará.
wsl nano /mnt/c/work/fun.ps1Por supuesto, quiero que las cosas sean simples y fáciles, por lo que necesitaré una función para convertir una ruta de Windows en la ruta montada en WSL. Primero, debería convertir la ruta de Windows en una ruta real del sistema de archivos. Esto ayudará a convertir rutas como .\file.txt o donde estoy usando un PSDrive como S:\remote.ps1.
$cPath = Convert-Path -Path $PathLuego dividiré esta ruta convertida en el directorio principal y el nombre del archivo.
$file = Split-Path -Path $cpath -Leaf
$dir = Split-Path -Path $cPath -ParentA continuación, quiero la parte de la ruta del directorio principal sin la letra de la unidad.
$folder = $dir.Substring(3)Estoy haciendo todo esto porque necesito construir la ruta correspondiente en Linux usando el punto de montaje.
"/mnt/{0}/{1}/{2}" -f $dir[0].tostring().ToLower(), $folder.replace("\", "/"), $fileEstoy creando una nueva cadena usando la primera letra del directorio principal. Como Linux distingue entre mayúsculas y minúsculas, lo estoy convirtiendo a minúsculas para que coincida con la ruta en Linux. La otra adaptación que tengo que hacer es cambiar todos los\a /.
Ahora el comando nano funciona como se esperaba.
Construyendo un conjunto de herramientas
Por supuesto, también creé una función de PowerShell para iniciar nano, teniendo en cuenta si quería editar un archivo existente o crear algo nuevo.
[string]$cmd = "wsl --exec nano"
if ($Path) {
$wslPath = ConvertTo-WSLPath -Path $Path
$cmd += " $wslPath"
}
#convert to a scriptblock
$sb = [scriptblock]::Create($cmd)
Invoke-Command -ScriptBlock $sbEste es el núcleo de la función.
Las últimas piezas que agregué estaban relacionadas con la validación. Mis funciones ConvertTo-WSLPath e Invoke-Nano están en un archivo .ps1 que tendré que poner en la fuente. Pero los comandos no se pueden usar si no hay instalación de WSL
$WslTest = ((wsl -l).split()).where({$_.length -gt 1}) -contains "(Default)"
If ( -Not $WslTest) {
Write-Warning "These commands require a WSL installation"
Return
}Descubrir esto requirió mucho más esfuerzo del que imaginaba. Puede ejecutar wsl -l para ver las instalaciones instaladas. Sin embargo, la codificación de la salida no es necesariamente la que ves en la consola. Mis esfuerzos por utilizar -Match o Select-String siguieron fallando. Finalmente, se me ocurrió este código para dividir los resultados del comando wsl en una matriz de cadenas con una longitud mayor que 1. Luego puedo usar -Contiene buscando '(Predeterminado)'. Si no se encuentra la cadena, mostraré una advertencia y luego saldré del script.
También quería verificar que quienquiera que obtenga el script se esté ejecutando en Windows, ya sea PowerShell 7 o Windows PowerShell. Mis funciones están definidas dentro de una declaración If.
if ($IsWindows -OR ($PSEdition -eq 'desktop')) {
#define functions
}
Else {
Write-Warning "These commands require a Windows platform"
}Si la consola de PowerShell es otra cosa, se muestra otra advertencia. ¿Quieres ver el resultado final?
# requires -version 5.1
#launch the nono text editor from a WSL installation like Ubuntu
# or install the Windows version https://sourceforge.net/projects/nano-for-windows/
# or https://sourceforge.net/projects/micro-for-windows/
# https://micro-editor.github.io/
if ($IsWindows -OR ($PSEdition -eq 'desktop')) {
#test if there is a default WSL installation
$WslTest = ((wsl -l).split()).where({$_.length -gt 1}) -contains "(Default)"
If ( -Not $WslTest) {
Write-Warning "These commands require a WSL installation"
Return
}
# a helper function to convert a Windows path to the WSL equivalent
Function ConvertTo-WSLPath {
[cmdletbinding()]
[outputtype("String")]
Param(
[Parameter(Position = 0, Mandatory, HelpMessage = "Enter a Windows file system path")]
[ValidateNotNullorEmpty()]
[string]$Path
)
Write-Verbose "[$($myinvocation.mycommand)] Starting $($myinvocation.mycommand)"
Write-Verbose "[$($myinvocation.mycommand)] Converting $Path to a filesystem path"
$cPath = Convert-Path -Path $Path
Write-Verbose "[$($myinvocation.mycommand)] Converted to $cpath"
$file = Split-Path -Path $cpath -Leaf
$dir = Split-Path -Path $cPath -Parent
$folder = $dir.Substring(3)
"/mnt/{0}/{1}/{2}" -f $dir[0].tostring().ToLower(), $folder.replace("\", "/"), $file
Write-Verbose "[$($myinvocation.mycommand)] Ending $($myinvocation.mycommand)"
}
#launch the nano editor from the WSL installation
Function Invoke-Nano {
[CmdletBinding()]
[outputtype("none")]
[alias("nano")]
Param(
[Parameter(Position = 0, HelpMessage = "Specify a text file path.")]
[ValidatenotNullorEmpty()]
[ValidateScript({ Test-Path $_ })]
[string]$Path
)
Write-Verbose "[$($myinvocation.mycommand)] Starting $($myinvocation.mycommand)"
[string]$cmd = "wsl --exec nano"
if ($Path) {
Write-Verbose "[$($myinvocation.mycommand)] Convert $Path"
$wslPath = ConvertTo-WSLPath -Path $Path
$cmd += " $wslPath"
}
Write-Verbose "[$($myinvocation.mycommand)] Using command expression $cmd"
#convert to a scriptblock
$sb = [scriptblock]::Create($cmd)
Write-Verbose "[$($myinvocation.mycommand)] Launch nano from the WSL installation"
Invoke-Command -ScriptBlock $sb
Write-Verbose "[$($myinvocation.mycommand)] Ending $($myinvocation.mycommand)"
}
}
Else {
Write-Warning "These commands require a Windows platform"
}Quiero señalar algo nuevo que estoy intentando con mis declaraciones detalladas. A menudo tengo funciones que llaman a otras funciones. En cada declaración detallada, incluyo el nombre del comando. Esto facilita el seguimiento del flujo.
Ahora puedo editar archivos rápidamente directamente desde la consola de PowerShell.
Y no, esto no reemplaza la funcionalidad que obtendría al usar VS Code o PowerShell ISE. Pero a veces sólo quiero hacer una edición rápida o tal vez ver el código fuente. Soy partidario del nano editor, pero puedes usar estos conceptos para iniciar vim o cualquier otro editor de texto que tengas instalado en tu instalación WSL.
Divertirse.




