2009-08-15 10 views
5

En Windows PowerShell, intento almacenar un comando de movimiento en una cadena y luego ejecutarlo. ¿Puede alguien decirme por qué esto no funciona?¿Por qué no puedo ejecutar un comando con argumentos de una cadena en powershell?

PS C:\Temp\> dir 
    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp 

Mode    LastWriteTime  Length Name 
----    -------------  ------ ---- 
-a---   8/14/2009 8:05 PM  2596 sa.csproj 
-a---   8/15/2009 10:42 AM   0 test.ps1 


PS C:\Temp> $str = "mv sa.csproj sb.csproj" 
PS C:\Temp> &$str 
The term 'mv sa.csproj sb.csproj' is not recognized as a cmdlet, function, operable program, or script file. Verify the 
term and try again. 
At line:1 char:2 
+ &$ <<<< str 
PS C:\Temp> 

Aparece este error al almacenar cualquier comando con argumentos. ¿Cómo supero esta limitación?

Respuesta

10

De la ayuda (about_Operators):

 
& Call operator 
    Description: Runs a command, script, or script block. Because the call 
    operator does not parse, it cannot interpret command parameters.

Se puede utilizar un bloque de script en lugar de una cadena:

$s = { mv sa.csproj sb.csproj } 
& $s 

o puede utilizar Invoke-Expression:

Invoke-Expression $str 

o

iex $str 

En contraste con &, Invoke-Expressionhace analizar el contenido de la cadena, por lo que puede poner cualquier cosa allí, no solo un comando.

+0

Gracias, ¿cree que se puede explicar (o enlace a) una explicación de lo que el personaje hace y? –

+2

'&' es para ejecutar un solo comando, script o scriptblock, al igual que los estados de ayuda. No hace ningún análisis sintáctico, por lo que solo acepta un único argumento que luego se supone que es un comando invocable. Si desea agregar parámetros, envuelva la llamada en un script o bloque de script o use 'Invoke-Expression'. Puede encontrar la página de ayuda que describe a los operadores escribiendo 'help about_operators' en Powershell. – Joey

5

Todas las sugerencias de Johannes son acertadas, pero quiero que la gente sepa que en la V2 hay otra opción. Se pone el mando en una cadena como antes, pero se pone los parámetros en una tabla hash y invoca usando & ej .:

$cmd = 'mv' 
$params = @{Path = 'log.txt'; Destination = 'log.bak'} 
&$cmd @params 

Esto utiliza una nueva característica denominada V2 splatting. Es como usar un archivo de respuesta para un comando, pero pones los parámetros en una tabla hash en lugar de un archivo.

Nota: También se puede poner los parámetros de una matriz que enchufar los parámetros "de posición" en lugar de por su nombre, por ejemplo:

$cmd = "cpi" 
$params = ('log.txt', 'log.bak') 
&$cmd @params 

No puede ajustar exactamente el problema de la OP, pero es una truco que vale la pena conocer.

2

tuviera que responder a una pregunta similar hace un tiempo acerca de cómo invocar un programa externo después de la creación de una lista de argumentos:

comprueban y se ve como el uso de . $program $argString o & $program $argString no funciona si $argString contiene múltiples argumentos . Los operadores . y & solo hacen una llamada directa, pasando el entero $argString como un único argumento.

En lugar de utilizar [string]$argString y haciendo $argString += "-aaa `"b b b`"", usted podría cambiarlo a [string[]]$argArray y utilizar $argArray += @('-aaa', 'b b b'), que va a funcionar y se escapará automáticamente las cadenas que sean necesarias.

También puede usar $process = [Diagnostics.Process]::Start($program, $argString). Esto facilitará el seguimiento del progreso de la ejecución, pero será más difícil recuperar cualquier salida de texto.

O puede poner todo en una cadena y usar Invoke-Expression "$program $argString", que analizará la cadena completa como un comando y la ejecutará correctamente.

Como se mencionó Keith, splatting es otra buena opción en PowerShell 2.

Cuestiones relacionadas