Làm cách nào để nối chuỗi và biến trong PowerShell?


610

Giả sử tôi có đoạn mã sau:

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

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

Tôi mong đợi đoạn trích này hiển thị:

42 - Slim Shady - Eminem

Nhưng thay vào đó, nó cho thấy:

42 + - + Slim Shady + - + Eminem

Điều này khiến tôi nghĩ rằng +toán tử không thích hợp để nối các chuỗi và biến.

Bạn nên tiếp cận điều này với PowerShell như thế nào?


28
Mã của bạn hoạt động nếu tất cả các phần tử là các chuỗi và bạn đặt biểu thức trong ngoặc đơn: Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) ở đây $ assoc.Id là một Int32vì vậy chúng ta phải sử dụng biểu diễn chuỗi của nó. Mặt khác, PS cố gắng thực hiện phép cộng số học thay vì nối.
bouvierr

5
Với số lượt xem tôi nghĩ rằng nó phù hợp để sửa chữa văn bản của câu hỏi này, mặc dù các chỉnh sửa của tôi đã thay đổi nội dung khá nhiều. Tôi đã cố gắng giữ nguyên thuật ngữ / từ ngữ và tinh thần của câu hỏi, đồng thời cải thiện nó đủ để nó có thể được mở lại.
Jeroen

Câu trả lời:


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

Xem Đặc tả ngôn ngữ Windows PowerShell Phiên bản 3.0 , p34, mở rộng biểu thức con.


1
Kỹ thuật này cũng hoạt động với Write-Output et al , vì vậy nó có thể là công cụ hữu ích nhất trong hộp công cụ của bạn.
Fenton

4
Tại sao $ ($ name) so với chỉ $ name? Đây có phải chỉ là phòng thủ theo cách tương tự như trong bash bằng cách sử dụng $ {name}?
Daniel Staple

73
Đây không phải là kỹ thuật nối.
TravisEz13

8
@DannyStaple câu hỏi đã được chỉnh sửa nhiều đến nỗi câu trả lời không còn ý nghĩa nữa. Trong ví dụ mờ ám, có "... $name ..."sẽ hoạt động như nhau, nhưng trong câu hỏi ban đầu mà câu trả lời này giải quyết, câu hỏi là làm thế nào để truy cập các thuộc tính đối tượng. Vì vậy, nếu $name.id -eq 42sau đó "... $name.id ..."sẽ không hoạt động như bạn muốn bởi vì nó sẽ hiển thị như thế ... @{id=42}.id ...thay vì mong muốn ... 42 ..., hãy sử dụng phương thức của câu trả lời "... $($name.id) ...". Tôi đang đánh dấu câu hỏi để chỉnh sửa sau.
Jeff Puckett

3
Cảm ơn rất nhiều vì đã chỉ cho tôi Thông số kỹ thuật ngôn ngữ PowerShell. Khi mới bắt đầu, tôi luôn bối rối về lý do tại sao PowerShell không đi kèm với một hướng dẫn chính thức. Thông số ngôn ngữ này trông giống như những gì tôi đang tìm kiếm. Cảm ơn một lần nữa!
RayLuo

256

Không ai có vẻ đã đề cập đến sự khác biệt giữa dấu ngoặc đơn và dấu ngoặc kép. (Tôi đang sử dụng PowerShell 4).

Bạn có thể làm điều này (như @Ben đã nói):

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

Hoặc bạn có thể làm điều này:

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

Các trích dẫn duy nhất là theo nghĩa đen, xin vui lòng xuất ra chuỗi chính xác như thế này. Dấu ngoặc kép là khi bạn muốn thực hiện một số xử lý trước (như biến, ký tự đặc biệt, v.v.)

Vì thế:

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

Trong khi:

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

( http://ss64.com/ps/syntax-esc.html Tôi thấy tốt để tham khảo).


1
Hoạt động với 1.0 cũng vậy.
Smit Johnth

134

Một cách là:

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

Một số khác là:

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

Hoặc chỉ (nhưng tôi không thích nó;)):

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

7
Tôi không nghĩ rằng cái cuối cùng hoạt động chính xác như bạn mong đợi. Xem pastebin ở đây . Powershell sẽ thêm một (mặc dù bạn có hai không gian ở đây) vào đầu ra cho khoảng trắng giữa $assoc.Id"(et al). Nghĩa là, tùy chọn 1 cung cấp cho bạn Id__-__Name__-__Owner(hai khoảng trắng ở mỗi bên của mỗi -), nhưng tùy chọn 3 cung cấp Id___-___Name___-___Owner( ba khoảng trắng).
ruffin

4
Có lẽ một pastebin hữu ích hơn . $assoc.Id"###"$assoc.Name sẽ thêm khoảng trắng vào hai bên của ###, trong đó "$($assoc.Id)###$($assoc.Name)" sẽ không .
ruffin 17/12/14

1
điều thứ hai đã thuyết phục tôi về quyền hạn là những gì tôi cần cho mục đích của mình - cảm ơn!
MaVCArt

123

Bạn cũng có thể dùng -join

Ví dụ

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

Sẽ gán "John" cho $ name.

Vì vậy, để đầu ra, trong một dòng:

Write-Host (-join("Jo", "h", "n"))

ít nhất cái này có thể được sử dụng trong foreach
dEmigOd

68

Hãy thử gói bất cứ thứ gì bạn muốn in ra trong ngoặc đơn:

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

Mã của bạn đang được hiểu là nhiều tham số được truyền đến Write-Host. Gói nó bên trong dấu ngoặc đơn sẽ nối các giá trị và sau đó chuyển giá trị kết quả dưới dạng một tham số.


3
+1, tôi thích định dạng này khi sử dụng các phương thức khác như Write-Debughoặc Write-Verboseđể bao gồm dấu ngoặc kép và giá trị biến, chẳng hạn nhưWrite-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear

Vâng, đây là nối chuỗi. Nó không thêm dòng mới hoặc không gian thêm. Nó cho phép bạn sử dụng một chuỗi hoặc hai chuỗi trích dẫn.
LexieHankins

Thủ thuật này là nối thực sự và cho phép bạn thực hiện các chuỗi nhiều dòng, giống như bạn làm trong .net. Rất tốt để làm các câu lệnh SQL đa dòng! Tại sao không có quyền hạn làm điều này theo mặc định!?
Brain2000

Có nhiều cách để làm. Nhưng đây là câu trả lời thực sự của nối chuỗi.
chingNotCHing

32

Một lựa chọn khác là:

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

Phương pháp "tốt nhất" có lẽ là phương pháp mà CB đề xuất:

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

3
Bạn cần thêm StringBuildertùy chọn nếu bạn đang phát điên. ; ^)
ruffin

2
chắc chắn có một cách để chuyển các thuộc tính mong muốn vào một tệp bên ngoài, sau đó giải tuần tự hóa chúng thành một chuỗi các thành phần được nối với dấu gạch nối (?)
Code

Thật khó để tưởng tượng một aproach tồi tệ hơn thế này. Các chuỗi là bất biến, do đó, mỗi hoạt động nối trong thực tế tạo ra một chuỗi mới, sao chép các ký tự của chuỗi gốc.
wombatonfire

22

Bạn cần đặt biểu thức trong ngoặc đơn để ngăn chúng được coi là các tham số khác nhau cho lệnh ghép ngắn:

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

Điều này là bắt buộc đối với Ghi-Gỡ lỗi
Frank

19

Trong khi biểu thức:

"string1" + "string2" + "string3"

sẽ nối các chuỗi. Bạn cần đặt $ trước dấu ngoặc đơn để làm cho nó đánh giá dưới dạng một đối số khi được truyền cho lệnh powershell. Thí dụ:

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

Như một phần thưởng, nếu bạn muốn nó trải dài trên nhiều dòng, thì bạn cần sử dụng cú pháp backtick khó hiểu ở cuối dòng (không có bất kỳ khoảng trắng hoặc ký tự nào ở bên phải của backtick). Thí dụ:

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

(Trên thực tế, tôi nghĩ rằng Powershell hiện đang thực hiện một chút sai lầm khi yêu cầu đánh dấu ngược không cần thiết giữa dấu ngoặc đơn. Nếu Microsoft chỉ tuân theo quy tắc ngoặc đơn "Python" hoặc "TCL" cho phép bạn đặt nhiều dòng mới như bạn muốn giữa bắt đầu và kết thúc dấu ngoặc đơn sau đó họ sẽ giải quyết hầu hết các vấn đề mà mọi người không thích về quyền hạn liên quan đến tiếp tục dòng và nối chuỗi. Tôi thấy rằng đôi khi bạn có thể bỏ dấu tích ngược trên dấu nối tiếp giữa dấu ngoặc đơn, nhưng nó thực sự hoàn hảo và không thể tin được nếu nó sẽ hoạt động .. tốt hơn là chỉ cần thêm các backticks.)


13

Đây là một cách khác để thay thế:

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

9

Tôi chỉ muốn mang đến một cách khác để làm điều này bằng .NET String.Format :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))

2
Có bất kỳ lợi thế của việc sử dụng .NET String.Formatthay vì đồng bằng cũ "{0}" -f $var? Tôi không thấy điểm nào trong việc sử dụng mã .NET nơi PowerShell đơn giản có thể thực hiện công việc ...
Dinei

4
@DineiRockenbach Có lẽ là không. Chỉ muốn đưa ra một ví dụ khác.
Martin Brandl

9

(Phiên bản PS hiện tại 5.1.17134.407)

Tôi đoán tất cả đã được nói và thực hiện nhưng điều này cũng hoạt động như bây giờ:

$myVar = "Hello"

echo "${myVar} World"

Lưu ý: điều này chỉ hoạt động với dấu ngoặc kép


7

Những câu trả lời này có vẻ rất phức tạp. Nếu bạn đang sử dụng điều này trong tập lệnh PowerShell, bạn chỉ cần làm điều này:

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

Nó sẽ xuất

Tên tôi la Slim Shady

Lưu ý cách đặt khoảng trắng giữa các từ cho bạn



6

Chuỗi liên kết giống như trong những ngày DOS. Đây là một vấn đề lớn để đăng nhập vì vậy bạn đi đây:

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

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday

Đối với ngày, tôi nghĩ rằng toStringtùy chọn dễ dàng hơn:(Get-Date).toString('yyyyMMdd')
Tony

6

Tôi dường như phải vật lộn với điều này (và nhiều thứ không trực quan khác) mỗi khi tôi sử dụng PowerShell sau thời gian rời xa nó, vì vậy bây giờ tôi chọn:

[string]::Concat("There are ", $count, " items in the list")

1
cái này trả về System.Object, fyi.
Barry

4

Write-Host cũng có thể ghép như thế này:

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

Đây là cách đơn giản nhất, IMHO.


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

2

Nếu bạn đang nối các chuỗi để tạo đường dẫn tệp, hãy sử dụng lệnh đường dẫn nối:

join-path C:\temp "MyNewFolder"

Nó sẽ tự động thêm dấu gạch chéo / dấu gạch chéo phù hợp cho bạn, giúp mọi việc dễ dàng hơn nhiều.

Tôi xin lỗi nếu điều này quá lạc đề, nhưng tôi nghĩ nó có thể giúp một số người.
Nếu tôi không sử dụng PowerShell trong một thời gian, đôi khi tôi sẽ quên nó tồn tại và bắt đầu tìm kiếm các toán tử ghép nối.


0

Bạn cũng có thể có quyền truy cập vào các phương thức C # /. NET và sau đây cũng hoạt động:

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

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

Output:

Slim Shady, The real slim shady

-2

Chỉ để cho vui. Bạn cũng có thể truy cập các giá trị của PSObject trực tiếp như bên dưới:

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

Nhưng nếu bạn không chỉ định rằng đối tượng nên được đặt hàng, Powershell sẽ hiển thị các giá trị theo thứ tự ngẫu nhiên. Vì vậy, nên thêm cờ [đã ra lệnh]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.