¿Cómo concateno cadenas y variables en PowerShell?

611

Supongamos que tengo el siguiente fragmento:

$assoc = New-Object psobject -Property @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}

Write-host $assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner

Esperaría que este fragmento se muestre:

42 - Slim Shady - Eminem

Pero en cambio muestra:

42 + - + Slim Shady + - + Eminem

Lo que me hace pensar que el +operador no es apropiado para concatenar cadenas y variables.

¿Cómo debería abordar esto con PowerShell?

Vaquera ninja
fuente
28
Su código funciona si todos los elementos son cadenas y encierra la expresión entre paréntesis: Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) aquí $ assoc.Id es un, Int32así que tenemos que usar su representación de cadena. De lo contrario, PS intenta realizar una suma aritmética en lugar de concatenación.
bouvierr
55
Dado el número de vistas, pensé que era apropiado reparar el texto de esta pregunta, a pesar de que mis ediciones cambiaron bastante el contenido. He tratado de mantener intacta la terminología / redacción y el espíritu de la pregunta, al tiempo que la he mejorado lo suficiente como para que pueda volver a abrirse.
Jeroen

Respuestas:

667
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"

Consulte la Especificación del lenguaje de Windows PowerShell Versión 3.0 , p34, expansión de subexpresiones.

David Brabant
fuente
1
Esta técnica también funciona con Write-Output et al , por lo que probablemente sea la más útil que tenga en su caja de herramientas.
Fenton
44
¿Por qué el $ ($ nombre) vs solo $ nombre? ¿Es esto solo defensivo de la misma manera que en bash usando $ {name}?
Danny Staple
73
Esto no es técnicamente concatenación.
TravisEz13
8
@DannyStaple, la pregunta se ha editado tanto que la respuesta ya no tiene sentido. En el ejemplo delgado y sombrío, sí "... $name ..."funcionará de todos modos, pero en la pregunta original a la que se dirige esta respuesta, la pregunta es cómo acceder a las propiedades del objeto. por lo que si $name.id -eq 42entonces "... $name.id ..."no funcionaría como que quiere porque haría que al igual que ... @{id=42}.id ...en lugar de la deseada ... 42 ...Para ello, utilizar el método de la respuesta "... $($name.id) ...". Estoy marcando una pregunta para editar más tarde.
Jeff Puckett
3
Muchas gracias por indicarme la especificación del lenguaje PowerShell. Como principiante, siempre me ha confundido por qué PowerShell no viene con un tutorial oficial. Esta especificación de idioma se parece a lo que estoy buscando. ¡Gracias de nuevo!
RayLuo
256

Nadie parece haber mencionado la diferencia entre comillas simples y dobles. (Estoy usando PowerShell 4).

Puedes hacer esto (como dijo @Ben):

$name = 'Slim Shady'
Write-Host 'My name is'$name
-> My name is Slim Shady

O puedes hacer esto:

$name = 'Slim Shady'
Write-Host "My name is $name"
-> My name is Slim Shady

Las comillas simples son para literal, emite la cadena exactamente así, por favor. Las comillas dobles son para cuando desea que se realice un procesamiento previo (como variables, caracteres especiales, etc.)

Entonces:

$name = "Marshall Bruce Mathers III"
Write-Host "$name"
-> Marshall Bruce Mathers III

Mientras:

$name = "Marshall Bruce Mathers III"
Write-Host '$name'
-> $name

( http://ss64.com/ps/syntax-esc.html me parece bueno como referencia).

TinyRacoon
fuente
1
Funciona con 1.0 también.
Smit Johnth
134

Una forma es:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"

Otro es:

Write-host  ("{0}  -  {1}  -  {2}" -f $assoc.Id,$assoc.Name,$assoc.Owner )

O simplemente (pero no me gusta;)):

Write-host $assoc.Id  "  -  "   $assoc.Name  "  -  "  $assoc.Owner
CB.
fuente
77
No creo que el último funcione exactamente como cabría esperar. Ver pastebin aquí . Powershell agregará un espacio (aunque tenga dos aquí) a la salida para el espacio en blanco entre $assoc.Idy "(et al). Es decir, la opción 1 le da Id__-__Name__-__Owner(dos espacios a cada lado de cada uno -), pero la opción 3 le da Id___-___Name___-___Owner( tres espacios).
ruffin
44
Quizás un pastebin más útil . $assoc.Id"###"$assoc.Name se agregue espacios a ambos lados de la ###, donde "$($assoc.Id)###$($assoc.Name)" no lo hará .
ruffin
1
El segundo me convenció de que PowerShell es lo que necesitaba para mis propósitos. ¡Gracias!
MaVCArt
123

También puedes usar -join

P.ej

$name = -join("Jo", "h", "n");

Asignaría "John" a $ name.

Entonces, a la salida, en una línea:

Write-Host (-join("Jo", "h", "n"))
Muchas maneras
fuente
al menos este podría usarse en foreach
dEmigOd
68

Intente envolver lo que quiera imprimir entre paréntesis:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)

Su código se interpreta como muchos parámetros que se pasan Write-Host. Envolviéndolo dentro de paréntesis concatenará los valores y luego pasará el valor resultante como un solo parámetro.

goric
fuente
3
+1, prefiero este formato cuando utilizo otros métodos como Write-Debugo Write-Verbosepara incluir comillas dobles y valores variables, comoWrite-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear
Sí, esto es concatenación de cadenas. No agrega nuevas líneas o espacios adicionales. Le permite usar cadenas de comillas simples o dobles.
LexieHankins
Este truco es una verdadera concatenación y le permite hacer cadenas de varias líneas, como lo haría en .net. Muy bueno para hacer declaraciones SQL multilínea! ¿Por qué PowerShell no hace esto por defecto?
Brain2000
Hay muchas formas de hacerlo. Pero esta es la verdadera respuesta de la concatenación de cadenas.
chingNotCHing
32

Otra opción es:

$string = $assoc.ID
$string += " - "
$string += $assoc.Name
$string += " - "
$string += $assoc.Owner
Write-Host $string

El "mejor" método es probablemente el que sugirió CB:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"
Frode F.
fuente
3
Necesitas agregar la StringBuilderopción si te estás volviendo loco concat. ; ^)
ruffin
2
seguramente hay una manera de canalizar las propiedades deseadas en un archivo externo, luego deserializarlas en una cadena de componentes unidos con guiones (?)
Code Jockey
Es difícil imaginar un enfoque peor que este. Las cadenas son inmutables, por lo que cada operación de concatenación de hecho produce una nueva cadena, copiando los caracteres de la original.
wombatonfire
22

Debe colocar la expresión entre paréntesis para evitar que se traten como parámetros diferentes del cmdlet:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)
Ricardo
fuente
Esto es obligatorio para Write-Debug
Frank
19

Mientras que la expresión:

"string1" + "string2" + "string3"

Concatenará las cuerdas. Debe poner un $ delante del paréntesis para que se evalúe como un argumento único cuando se pasa a un comando de PowerShell. Ejemplo:

Write-Host $( "string1" + "string2" + "string3" ) 

Como beneficio adicional, si desea que abarque varias líneas, debe usar la sintaxis de retroceso al final de la línea (sin espacios ni caracteres a la derecha del retroceso). Ejemplo:

Write-Host $(`
    "The rain in "        +`
    "Spain falls mainly " +`
    "in the plains"       )`
    -ForegroundColor Yellow

(En realidad, creo que Powershell se implementa actualmente un poco mal porque requiere retrocesos innecesarios entre paréntesis. Si Microsoft simplemente siguiera las reglas "Python" o "TCL" Paréntesis de permitirle poner tantas líneas nuevas como desee entre el inicio y terminando el paréntesis, entonces resolverían la mayoría de los problemas que a la gente no le gusta sobre PowerShell relacionado con la continuación de línea y la concatenación de cadenas.He descubierto que a veces puede dejar atrás los ticks en las continuaciones de línea entre paréntesis, pero realmente flakey e impredecible si funcionará ... es mejor simplemente agregar los backticks).

Bill Moore
fuente
13

Aquí hay otra forma como alternativa:

Write-host (" {0}  -  {1}  -  {2}" -f $assoc.Id, $assoc.Name, $assoc.Owner)
Dave Sexton
fuente
9

Solo quiero traer otra forma de hacer esto usando .NET String.Format :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))
Martin Brandl
fuente
2
¿Hay alguna ventaja de usar .NET en String.Formatlugar del viejo plano "{0}" -f $var? No veo el punto de usar el código .NET donde PowerShell puede hacer el trabajo ...
Dinei
44
@DineiRockenbach Probablemente no. Solo quería mencionar otro ejemplo.
Martin Brandl
9

(Versión actual de PS 5.1.17134.407)

Todo está dicho y hecho ahora, supongo, pero esto también funciona a partir de ahora:

$myVar = "Hello"

echo "${myVar} World"

Nota: esto solo funciona con comillas dobles

Benjamín
fuente
7

Todas estas respuestas parecen muy complicadas. Si está usando esto en un script de PowerShell, simplemente puede hacer esto:

$name = 'Slim Shady'
Write-Host 'My name is'$name

Saldrá

Mi nombre es Slim Shady

Observe cómo se coloca un espacio entre las palabras para usted

elev8ed
fuente
6

Concatenar cadenas como en los días de DOS. Este es un gran problema para iniciar sesión, así que aquí tienes:

$strDate = Get-Date
$strday = "$($strDate.Year)$($strDate.Month)$($strDate.Day)"

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
Kelly Davis
fuente
Para las fechas, creo que la toStringopción es más fácil:(Get-Date).toString('yyyyMMdd')
Tony hace
6

Parece que tengo problemas con esto (y muchas otras cosas poco intuitivas) cada vez que uso PowerShell después de un tiempo alejado de él, así que ahora opto por:

[string]::Concat("There are ", $count, " items in the list")
Luke Puplett
fuente
1
esto devuelve System.Object, fyi.
Barry
4

Write-Host también puede concatenar así:

Write-Host $assoc.Id" - "$assoc.Name" - "$assoc.Owner

Esta es la forma más simple, en mi humilde opinión.

Mordechai
fuente
2
$assoc = @{
    Id = 34
    FirstName = "John"
    LastName = "Doe"
    Owner = "Wife"
}

$assocId = $assoc.Id
$assocFN = $assoc.FirstName
$assocLN = $assoc.LastName
$assocName = $assocFN, $assocLN -Join " "
$assocOwner = $assoc.Owner

$assocJoin = $assocId, $assocName, $assocOwner -join " - "
$assocJoin
#Output = 34 - John Doe - Wife
blayderunner123
fuente
2

Si está concatenando cadenas para construir rutas de archivos, use el comando join-path:

join-path C:\temp "MyNewFolder"

Agregará automáticamente las barras inclinadas / iniciales apropiadas para usted, lo que hace las cosas mucho más fáciles.

Pido disculpas si esto está demasiado fuera de tema, pero pensé que podría ayudar a algunos.
Si no uso PowerShell por un tiempo, a veces olvidaré que existe y comenzaré a buscar los operadores de concatenación.

squicc
fuente
0

También puede obtener acceso a los métodos C # / .NET, y lo siguiente también funciona:

$string1 = "Slim Shady, "
$string2 = "The real slim shady"

$concatString = [System.String]::Concat($string1, $string2)

Output:

Slim Shady, The real slim shady
Ian Robertson
fuente
-2

Solo por diversión. También puede acceder a los valores del PSObject directamente como se muestra a continuación:

$assoc.psobject.Properties.value -join " - "

Pero si no especifica que se debe ordenar el objeto, Powershell mostrará los valores en un orden aleatorio. Entonces debería agregar la bandera [ordenada]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}
R.Amersfoort
fuente