2009-08-15 19 views
5

Trong cửa sổ PowerShell, tôi đang cố gắng lưu trữ một lệnh di chuyển trong một chuỗi và sau đó thực hiện nó. Ai đó có thể cho tôi biết lý do tại sao điều này không hoạt động?Tại sao tôi không thể thực hiện một lệnh với các đối số từ một chuỗi trong 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> 

Tôi gặp lỗi này khi lưu trữ bất kỳ lệnh nào có đối số. Làm cách nào để vượt qua giới hạn này?

Trả lời

10

Từ sự giúp đỡ (about_Operators):

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

Bạn có thể sử dụng một khối kịch bản thay vì một chuỗi:

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

Hoặc bạn có thể sử dụng Invoke-Expression:

Invoke-Expression $str 

hoặc

iex $str 

Ngược lại với &, Invoke-Expressionlàm phân tích nội dung chuỗi, để bạn có thể đặt bất kỳ thứ gì vào đó, không chỉ một lệnh.

+0

Cảm ơn, làm bạn nghĩ rằng bạn có thể giải thích (hoặc liên kết tới) giải thích về những gì các nhân vật & không? –

+2

'&' là để thực hiện một lệnh, tập lệnh hoặc scriptblock, giống như các trạng thái trợ giúp. Nó không thực hiện bất kỳ phân tích cú pháp nào để nó chỉ chấp nhận một đối số duy nhất mà sau đó được giả định là một lệnh không thể giải mã được. Nếu bạn muốn thêm các tham số, sau đó hoặc là bọc cuộc gọi trong một kịch bản hoặc khối tập lệnh hoặc sử dụng 'Invoke-Expression'. Bạn có thể tìm trang trợ giúp mô tả toán tử bằng cách gõ 'help about_operators' trong Powershell. – Joey

5

Tất cả đề xuất của Johannes đều được phát hiện nhưng tôi muốn làm cho mọi người biết rằng trong phiên bản V2, có một tùy chọn khác. Bạn đặt các lệnh trong một chuỗi như trước nhưng bạn đặt các thông số trong một Hashtable và gọi sử dụng & ví dụ .:

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

này sử dụng một tính năng mới gọi là V2 splatting. Nó là loại giống như sử dụng một tập tin phản ứng cho một lệnh nhưng bạn đặt các tham số trong một hashtable thay vì một tập tin.

Lưu ý: bạn cũng có thể đặt các thông số trong một mảng mà sẽ cắm vào các thông số "bởi vị trí" chứ không phải là theo tên ví dụ:

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

Nó có thể không chính xác phù hợp với vấn đề của OP nhưng nó là một lừa đáng biết.

2

tôi phải trả lời một câu hỏi tương tự một khi trở lại về cách gọi một chương trình bên ngoài sau khi xây dựng một danh sách các đối số:

Kiểm tra và có vẻ như sử dụng . $program $argString hoặc & $program $argString không hoạt động nếu $argString chứa nhiều tranh cãi . Các toán tử .& chỉ thực hiện cuộc gọi trực tiếp, chuyển toàn bộ số $argString làm một đối số.

Thay vì sử dụng [string]$argString và làm $argString += "-aaa `"b b b`"", bạn có thể thay đổi nó để [string[]]$argArray và sử dụng $argArray += @('-aaa', 'b b b'), mà sẽ làm việc và sẽ tự động thoát khỏi chuỗi khi cần thiết.

Bạn cũng có thể sử dụng $process = [Diagnostics.Process]::Start($program, $argString). Điều này sẽ giúp việc theo dõi tiến độ thực hiện dễ dàng hơn, nhưng khó lấy lại bất kỳ đầu ra văn bản nào.

Hoặc bạn có thể đặt mọi thứ vào chuỗi và sử dụng Invoke-Expression "$program $argString", sẽ phân tích cú pháp toàn bộ chuỗi dưới dạng lệnh và thực thi chính xác.

Như Keith đề cập, splatting là một lựa chọn tốt trong PowerShell 2.

Các vấn đề liên quan