2013-08-29 43 views
5

Tôi đã làm việc trên một số kịch bản PowerShell và tìm thấy một vài điều kỳ lạ. Tôi có một tập lệnh chấp nhận 4 tham số bắt buộc: hai chuỗi và hai Booleans.Tại sao giá trị boolean của tôi 0 trở lại đúng?

.\[scriptname] [string1] [string2] [bool1] [bool2]

Điều này làm việc tốt và tôi đã kiểm tra xem chúng có được truyền chính xác không.

Tuy nhiên, tôi đã tìm thấy điều gì đó khá lạ khi PowerShell yêu cầu tham số; nó đặt cả hai booleans thành true.

.\[scriptname] [string1] [string2] 
please enter bool1: 0 
please enter boo2: 0 

Sau đó, chạy tập lệnh như thể bool1 và bool2 được đặt thành true và không phải là những gì tôi đã đặt. Tôi đã thực sự vượt qua mọi thứ khác nhau, và nó luôn luôn là kết quả đúng.

Tôi không chắc chắn lý do tại sao điều này xảy ra và muốn biết liệu có ai đã gặp phải nguyên nhân hoặc giải pháp cho vấn đề kỳ quái này không!

Tôi cũng thấy rằng Trình lập lịch tác vụ có vấn đề tương tự. Hãy thiết lập nó

powershell -file [scriptlocation] [string1] [string2] [bool1] [bool2]

dụ:

PowerShell -file "C: \ script1.ps1" "c: \ fileOne.txt" "c: \ folder1" 0 0

Cả hai phép toán đều đi qua dưới dạng chuỗi.

+3

Vui lòng đăng nguồn hiển thị hành vi này – Eris

+0

Nó không thực sự để làm với mã nguồn của tôi, như tất cả tôi đang làm là đi qua chúng như là tham số bắt buộc. Moot của nó những gì xảy ra với phần còn lại của kịch bản. – Hazz22

+1

Hy vọng rằng bạn có thể thấy lợi ích khi đăng mã của mình ngay bây giờ. Nó có thể không có vẻ ngay lập tức có liên quan để làm như vậy, nhưng nó mang lại cho chúng ta bối cảnh quan trọng để có thể tái tạo vấn đề của bạn và giúp bạn sớm hơn. :) –

Trả lời

13

This blog bởi Jeffrey Snover cung cấp một số thông tin chi tiết về hành vi của các boolean trong Powershell. Dưới đây là một đoạn trích, nơi ông tạo ra một chức năng đơn giản "test" để trở về đúng hay sai tùy thuộc vào các tham số đầu vào:

PS> test "0" 
TRUE 
PS> test 0 
FALSE 
PS> test 1 
TRUE 
PS> test 0.0 
FALSE 
PS> test 0x0 
FALSE 
PS> test 0mb 
FALSE 
PS> test 0kb 
FALSE 
PS> test 0D 
FALSE 
PS> test 0.00000001 
TRUE 

“0” là TRUE vì nó là một STRING và nó có một chiều dài 1. 0 là FALSE vì nó là một số và số đó là 0. Trong PowerShell, bất kỳ số nào đánh giá là 0 là FALSE và mọi số khác không là TRUE. Ví dụ này cho bạn thấy một điểm 0 không nổi, một hệ thập lục phân không, 0 megs, 0 kilos, 0 thập phân, có tất cả các số 0 nhưng đến PowerShell, tất cả đều được đánh giá là FALSE.

Không có mã mẫu nào khó nói chính xác những gì đang diễn ra, nhưng những gì chúng tôi có thể nói là đầu vào của bạn không được Powershell xác định là 0. Có lẽ nó là một chuỗi? Điều này sẽ đúng nếu bạn sử dụng Read-Host để nhận dữ liệu nhập của người dùng. Dưới đây là một ví dụ:

PS C:\> $test = Read-Host "Input" 
Input: 0 
PS C:\> $test.GetType() 

IsPublic IsSerial Name          BaseType 
-------- -------- ----          -------- 
True  True  String         System.Object 

PS C:\> test $test 
TRUE 

PS C:\> $test = [Int32]$test 
PS C:\> test $test 
FALSE 

Bạn có thể kiểm tra bằng cách sử dụng GetType() trên biến trong câu hỏi, và sửa chữa nó có thể là một vấn đề đơn giản của một cách rõ ràng đúc để loại mong muốn.

Tôi càng đọc câu hỏi của bạn nhiều hơn - trừ khi tôi đã hiểu lầm nó - điều này dường như giải quyết các vấn đề của bạn. Đặc biệt là nơi bạn nhận xét rằng bạn đã "vượt qua mọi thứ khác nhau" vì bất kỳ chuỗi độ dài khác 0 nào sẽ đánh giá đúng trong ngữ cảnh này.

PS C:\> $anotherTest = "42" 
PS C:\> test $anotherTest 
TRUE 
PS C:\> $anotherTest = [Int32]$anotherTest 
PS C:\> test $anotherTest 
TRUE 

Edit: Alright, tôi đã làm việc nhiều hơn một chút về vấn đề bây giờ là tôi có một số ý tưởng những gì môi trường của bạn là. Đầu tiên, mọi thứ tôi nói với bạn ở trên là đúng, vì vậy xin đừng bỏ qua nó. Vấn đề bạn gặp phải là việc chuyển đổi kiểu boolean đang xử lý đầu vào dấu nhắc bắt buộc powershell theo cách không rõ ràng ngay lập tức.

Vì vậy, một số tình hình tồn tại nơi đoạn mã này:

param 
(
    [Parameter(mandatory=$true)][bool]$myBool 
) 
Write-Host $myBool 

sẽ gây ra kết quả sau khi bạn sử dụng dấu nhắc tham số bắt buộc PowerShell thay vì nộp biến trên dòng lệnh:

PS C:\> .\script.ps1 
cmdlet script.ps1 at command pipeline position 1 
Supply values for the following parameters: 
myBool: 0 
True 

Lết tôi lặp lại: Trong Powershell, tất cả các chuỗi không có chiều dài rỗng được đánh giá là đúng. Điều này bao gồm "0" và điều này bao gồm các chuỗi ký tự. Nhưng vấn đề là gì? Chúng tôi đã tuyên bố rõ ràng biến của chúng tôi là bool, vì vậy, nó phải hiểu rằng tôi có nghĩa là 0, phải không?

Sai. Một tình huống khá không may được tạo ra nơi chúng ta đang mong đợi một bool, hoặc ít nhất là một chuỗi, khi chúng ta thiết lập đầu vào của chúng ta tới dấu nhắc. Chúng tôi thực sự cuối cùng nhận được bool, nhưng hãy nhớ những gì sẽ xảy ra với các chuỗi không null khi chúng tôi chuyển đổi chúng để bools? Chuyển đổi kiểu thành bool đang được áp dụng cho đầu vào theo nghĩa đen mà bạn đặt ở dấu nhắc, đây không phải là kiểu số. Vì đầu vào có độ dài không null, phép chuyển đổi bool sẽ được đánh giá là true. Về cơ bản, bạn thực hiện thao tác này:

PS C:\> [bool]$myBool = [bool]"0" 
PS C:\> $myBool 
True 

Vấn đề lớn với điều này là vì chúng tôi đã chuyển đổi biến thành bool, chuỗi đã được sử dụng và chúng tôi chỉ còn lại giá trị 1 hoặc Thật. Vì vậy, "0" của bạn theo nghĩa đen đã biến thành 1. Chúng tôi không thể lấy lại 0 nữa. Chúng ta nên làm gì? Tôi sẽ liệt kê một vài tùy chọn:

  • Đặt biến của bạn là [int] loại thay vì [bool]. Việc chuyển đổi bool tiêu thụ chuỗi "0" và biến nó thành 1, vậy tại sao không sử dụng một loại mà sẽ không làm điều đó? Powershell hiểu số 0 và số 1 là đúng và sai, vì vậy bạn có thể sử dụng bất kỳ loại số nào.

Ví dụ với sản lượng:

param 
(
    [Parameter(mandatory=$true)][int]$myBool 
) 
Write-Host $myBool 

PS C:\> .\script1.ps1 
cmdlet script1.ps1 at command pipeline position 1 
Supply values for the following parameters: 
myBool: 0 
0 
  • Nếu bạn đang sử dụng bools như công tắc logic, xem xét các loại [switch] tham số để thay thế. Công tắc luôn luôn đánh giá sai, trừ khi bạn đặt chúng một cách rõ ràng. Bạn không nên để lộ lời nhắc theo cách này, vì vậy bạn sẽ không gặp phải vấn đề này. Thông tin thêm here.
+1

Giải thích tốt về các loại đầu vào khác nhau. – Mitul

+0

Cảm ơn lời giải thích. Tuy nhiên, điều này không hoàn toàn trả lời câu hỏi của tôi. Những gì tôi hỏi là tại sao nó thay đổi từ chấp nhận 0 và 1 dọc theo dòng lệnh là đúng và sai, nhưng khi nó yêu cầu các lệnh thì nó quyết định chúng là đúng? – Hazz22

+0

Sự khác biệt giữa dòng lệnh và lệnh ghép ngắn là dòng lệnh đủ thông minh để giải thích rõ ràng đầu vào của bạn - cmdlet, mặt khác, có kiểu trả về nghiêm ngặt. Tôi có thể bình luận thêm nếu tôi biết những gì bạn đang sử dụng cmdlet, nhưng nó trông giống như Read-Host. Kiểm tra [tài liệu này] (http://technet.microsoft.com/en-us/library/hh849945.aspx) trên Read-Host, đầu ra là System.String ngay cả khi bạn đặt trong một giá trị số. Bạn sẽ cần phải rõ ràng "bỏ" chuỗi đó vào một số kiểu số, như một int, cho nó để hiểu rằng bạn có nghĩa là 0 và không "0". –

0

nếu chức năng của bạn không chấp nhận tham số là boolean, điều đó có thể giải thích tại sao điều này xảy ra (Hyper Anthony đã giải thích rõ điều này).

Vì vậy, tập lệnh của bạn có tham số ([string] x1, [string [x2], [bool] y1, [bool] y2) loại khai báo không?Trong trường hợp đó y1 và y2 sẽ là boolean, nhưng nếu không có thể được coi là chuỗi có giá trị 0, trong trường hợp nó được coi là "0" không bằng 0

+0

Tất cả các tham số bắt buộc đã được đặt rõ ràng, điều này khiến cho điều này trở nên hơi kỳ quặc. Tôi sẽ đăng một số mã ví dụ sau, để hiển thị ý tôi. – Hazz22

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