2016-01-22 52 views
0

我不是Windows的傢伙,來自Linux的一面。 我的問題是,我該如何編寫一個批處理文件,將一個可選開關作爲布爾值或值參數?例如:如何創建一個採用可選參數的批處理文件

ssh.cmd/X /升登錄遠程主機

在哪裏/ X是一個布爾開關的意思是「打開特徵X」和/升是一個「值開關」,這意味着對下一個標記命令行將以特殊方式使用。例如,在UNIX中,你可以這樣做:

的ssh -l -X登錄遠程主機

這裏,-X是一個布爾告訴ssh的轉發X端口,和-l是「價值交換」的告訴ssh我的用戶名是「login」。 remotehost是一個強制性的參數。我知道如何處理這些命令文件中的最後一個,並且無法在Google地球的任何位置找到解決方案。

我在想這樣做的唯一方法是痛苦地通過尋找符合正確格式的字符串的說法,並說「啊哈發現了一個開關!」那是對的嗎?

在此先感謝。

+3

看看http://stackoverflow.com/a/8162578/1012053 – dbenham

+0

阿哈,容易錯過,但好評,謝謝。 – Rich

回答

3

下面是否認未識別開關的另一種選擇,可同時接收/-爲有效開關前綴,執行不區分大小寫的開關檢查,和坪REMOTEHOST以檢查有效性。

@echo off 
setlocal enabledelayedexpansion 

if not "%~1"=="" goto :switches 

:usage 
echo Usage: %~nx0 [/X] [/L loginname] remotehost 
goto :EOF 

:switches 
rem // make sure variables are undefined 
for %%I in (forward login host switch valid) do set "%%I=" 

rem // loop through all arguments 
for %%I in (%*) do (

    rem // if this iteration is a value for the preceding switch 
    if defined switch (

     rem // if that switch was -L or /L (case-insensitive) 
     if /i "!switch:~1!"=="L" set "login=%%~I" 

     rem // clear switch variable 
     set "switch=" 

    ) else (

     rem // if this iteration is a switch 
     echo(%%~I | >NUL findstr "^[-/]" && (

      set "switch=%%~I" 

      rem // if this is a valid switch 
      for %%x in (X L) do (
       if /i "!switch:~1!"=="%%x" set "valid=true" 
      ) 

      if not defined valid (
       echo Unrecognized switch: %%~I 
       goto usage 
      ) 

      set "valid=" 

      if /i "!switch:~1!"=="X" (
       set "forward=true" 
       set "switch=" 
      ) 
     ) || (

      rem // not a switch. Must be a host. 
      ping -n 1 %%~I | findstr /i "^Reply.*time.*[0-9]" >NUL && (
       set "host=%%~I" 
      ) || (
       echo Host %%~I is unreachable. 
      ) 
     ) 
    ) 
) 

if not defined host goto usage 

<NUL set /P "=Args passed: " 
if defined forward <NUL set /P "=FORWARD " 
if defined login <NUL set /P "=LOGIN %login% " 
echo %host% 

而且你知道,如果你不舒服的腳本的Windows批處理腳本,你可能會考慮其他腳本語言。許多人會建議PowerShell,這是一個有價值的選擇。但是,如果您不想學習全新的語言和格式,如果您熟悉JavaScript,JScript就非常相似。我會示範,我希望你能看到相似之處。用.js擴展名保存。要運行它,做cscript /nologo scriptname.js switches here

// convert WSH.Arguments object to a JS array 
for (var args=[], i=0; i<WSH.Arguments.Length; i++) 
    args.push(WSH.Arguments(i)); 

function error(txt, code) { 
    WSH.StdErr.WriteLine(txt); 
    WSH.StdErr.WriteLine('Usage: '+WSH.ScriptName+' [/X] [/L loginname] remotehost'); 
    WSH.Quit(code); 
} 

for (var i=0; i<args.length; i++) { 
    switch (args[i].toLowerCase().replace("-","/")) { 

     case "/x": 
      var forward = true; 
      break; 

     case "/l": 
      if (++i == args.length || /^\//.test(args[i])) 
       error('Invalid login name.', 1); 
      else var login = args[i]; 
      break; 

     default: 
      if (/^\//.test(args[i])) 
       error('Unrecognized option: ' + args[i], 2); 
      else var host = args[i]; 
    } 
} 

if (!host) error('No host specified.', 3); 

WSH.Echo([ 
    'Command: ', 
    (forward ? 'FORWARD ' : ''), 
    (login ? 'LOGIN ' + login + ' ' : ''), 
    host 
].join('')); 

JScript和JavaScript的有很多共通之處。您可以調用相同的RegExp對象方法和Array對象方法,修改原型,將數據強制爲兼容的數據類型或測試其真實性等等。 JScript JavaScript,只是帶有「WScript」(或「WSH」代表懶惰)的根祖先對象而不是「Window」。

// convert WSH.Arguments proprietary object to a JS array 
for (var args=[], i=0; i<WSH.Arguments.Length; i++) 
    args.push(WSH.Arguments(i)); 

function error(txt, code) { 
    WSH.StdErr.WriteLine(txt); 
    WSH.StdErr.WriteLine('Usage: '+WSH.ScriptName+' [/X] [/L loginname] remotehost'); 
    WSH.Quit(code); 
} 

// returns idx of array element matching rxp (or -1 if no match) 
Array.prototype.match = function(rxp) { 
    for (var i=this.length; i--;) if (rxp.test(this[i])) return i; 
    return -1; 
} 

var X = args.match(/^[/-]X$/i); 
if (X > -1) var forward = args.splice(X, 1)[0]; 

var L = args.match(/^[/-]L$/i); 
if (L > -1) var login = args.splice(L, 2)[1]; 

for (var invalid=[], i=args.length; i--;) 
    if (/^[/-]/.test(args[i])) invalid.push(args[i]); 

if (invalid.length) error('Unrecognized option: ' + invalid.join(), 1); 
if (!args.length) error('No host specified.', 2); 

WSH.Echo([ 
    'Params: ', 
    (forward ? 'FORWARD ' : ''), 
    (login ? 'LOGIN ' + login + ' ' : ''), 
    args[0] 
].join('')); 

如果你想用這些參數來啓動外部程序,看看objShell.Run


如果你想你的腳本部署到其他用戶,使它成爲一個批處理+ JScript的混合格式,並用.bat擴展名保存它使得它更人性化的執行。只需將它放在上述任一解決方案的頂部,然後以.bat擴展名保存腳本。

@If (@CodeSection == @Batch) @then 
@echo off & setlocal 
cscript /nologo /e:JScript "%~f0" %* 
goto :EOF 
@end // end Batch/begin JScript hybrid chimera 
// JScript code here 

它的工作方式是首先用cmd批解釋器加載腳本。由於(@CodeSection不等於@Batch),該行的其餘部分永遠不會嘗試。繼續執行直至cscript行,該行使用JScript解釋器重新加載此腳本,並傳遞命令行參數。

JScript確定@CodeSection實際上不等於@Batch,並跳到@end。在JScript執行結束時,cscript.exe退出並且批處理線程繼續執行直到goto :EOFexit /b

隨着混合代碼的添加,現在的語法是scriptname.bat arguments here。如果您想繞過批處理代碼並只執行JScr​​ipt部分,則cscript /nologo /e:JScript scriptname.bat argumentss here也可以使用。

+0

謝謝!我必須能夠依靠每個有能力運行我的小黑客腳本而無需安裝任何額外工具的用戶。 jscript是一個標準的DOS工具,這樣我就可以給用戶一個.jscript文件,他們可以直接運行它,而不需要做任何事情?如果是這樣,哪些版本的Windows支持它? – Rich

+0

JScript是一種Windows腳本宿主語言,與VB腳本一樣,但使用ECMAScript方法和語法。每個Windows版本都支持它。有一個巧妙的技巧可以用來爲其他用戶部署腳本,製作Batch + JScript混合嵌合體。我會編輯我的答案並解釋。 – rojo

+0

謝謝,這是非常有趣和有用的信息。 – Rich

2
@echo off 
setlocal EnableDelayedExpansion 

rem Define the "value switches" 
set "valSwitch=L M N" 

rem Load parameters in "switch" and "argv" vectors 
set "argc=0" 

:nextParam 
    set "param=%~1" 
    if "%param:~0,1%" equ "/" (

     rem Is a switch 
     for %%s in (%param:~1,1%) do (
     if "!valSwitch:%%s=!" equ "%valSwitch%" (
      rem Is a boolean switch 
      set "switch[%%s]=True" 
     ) else (
      rem Is a value switch 
      set "switch[%%s]=%~2" 
      shift 
     ) 
    ) 

    ) else (

     rem Is a standard parameter 
     set /A argc+=1 
     set "argv[!argc!]=%~1" 

    ) 

    shift 
if "%~1" neq "" goto nextParam 

SET SWITCH 
SET ARGV 

輸出例如:

C:\Users\Antonio\Test> test.bat /X /l login remotehost 
switch[l]=login 
switch[X]=True 
argv[1]=remotehost 

C:\Users\Antonio\Test> test.bat /X remotehost /l login 
switch[l]=login 
switch[X]=True 
argv[1]=remotehost 

C:\Users\Antonio\Test> test.bat remotehost /l login /X 
switch[l]=login 
switch[X]=True 
argv[1]=remotehost 

C:\Users\Antonio\Test> test.bat /Y /A /M "login1 login2" remotehost "last parameter" 
switch[A]=True 
switch[M]=login1 login2 
switch[Y]=True 
argv[1]=remotehost 
argv[2]=last parameter 
+0

謝謝,這是一個完全可以接受的解決方案,我只能一次只接受一個顯然! :-)乾杯。 – Rich

+0

是的,但是如果你願意的話,你可以取消你之前的選擇,以便製作一個新的選擇! **')** ** – Aacini

+0

不幸的是,你是第二位的,你不得不承認羅霍給出了相當完整和有用的答案。雖然謝謝! – Rich

相關問題