簡體   English   中英

是否可以編寫一個在 bash/shell 和 PowerShell 中運行的腳本?

[英]Is it possible to write one script that runs in bash/shell and PowerShell?

我需要創建一個集成腳本來設置一些環境變量,使用 wget 下載文件並運行它。

挑戰在於它必須是可以在 Windows PowerShell 和 bash / shell 上運行的相同腳本。

這是外殼腳本:

#!/bin/bash
# download a script
wget http://www.example.org/my.script -O my.script
# set a couple of environment variables
export script_source=http://www.example.org
export some_value=floob
# now execute the downloaded script
bash ./my.script

這在 PowerShell 中是一樣的:

wget http://www.example.org/my.script -O my.script.ps1
$env:script_source="http://www.example.org"
$env:some_value="floob"
PowerShell -File ./my.script.ps1

所以我想知道這兩個腳本是否可以以某種方式合並並在任一平台上成功運行?

我一直在嘗試找到一種方法將它們放在同一個腳本中並讓 bash 和 PowerShell.exe 忽略錯誤,但這樣做沒有成功。

有什么猜測嗎?

有可能的; 我不知道這有多兼容,但 PowerShell 將字符串視為文本,它們最終出現在屏幕上,Bash 將它們視為命令並嘗試運行它們,並且兩者都支持相同的函數定義語法。 因此,將函數名稱放在引號中,只有 Bash 會運行它,將“exit”放在引號中,只有 Bash 會退出。 然后編寫PowerShell代碼。

注意。 這是有效的,因為兩個 shell 中的語法重疊,並且您的腳本很簡單 - 運行命令並處理變量。 如果您嘗試對任一語言使用更高級的腳本(if/then、for、switch、case 等),另一個可能會抱怨。

將其保存為dual.ps1以便 PowerShell 對它感到滿意, chmod +x dual.ps1以便 Bash 運行它

#!/bin/bash

function DoBashThings {
    wget http://www.example.org/my.script -O my.script
    # set a couple of environment variables
    export script_source=http://www.example.org
    export some_value=floob
    # now execute the downloaded script
    bash ./my.script
}

"DoBashThings"  # This runs the bash script, in PS it's just a string
"exit"          # This quits the bash version, in PS it's just a string


# PowerShell code here
# --------------------
Invoke-WebRequest "http://www.example.org/my.script.ps1" -OutFile my.script.ps1
$env:script_source="http://www.example.org"
$env:some_value="floob"
PowerShell -File ./my.script.ps1

然后

./dual.ps1

在任一系統上。


編輯:您可以通過用不同的前綴注釋代碼塊來包含更復雜的代碼,然后讓每種語言過濾出自己的代碼並對其進行eval (通常的安全警告適用於 eval),例如使用這種方法(結合Harry Johnston 的建議) :

#!/bin/bash

#posh $num = 200
#posh if (150 -lt $num) {
#posh   write-host "PowerShell here"
#posh }

#bash thing="xyz"
#bash if [ "$thing" = "xyz" ]
#bash then
#bash echo "Bash here"
#bash fi

function RunBashStuff {
    eval "$(grep '^#bash' $0 | sed -e 's/^#bash //')"
}

"RunBashStuff"
"exit"

((Get-Content $MyInvocation.MyCommand.Source) -match '^#posh' -replace '^#posh ') -join "`n" | Invoke-Expression

雖然另一個答案很棒
(感謝TessellatingHecklerHarry Johnston

我們實際上可以做得更好

  1. 使用更多 shell(例如為 Ubuntu 的 dash 工作)
  2. 在未來的情況下不太可能破裂
  3. 無需浪費處理時間重新讀取/評估腳本
  4. 在令人困惑的語法上浪費更少的字符/行
    (我們只需要 26 個字符和 3 行就可以逃脫)
  5. 即使保持語法高亮功能

復制粘貼代碼

#!/usr/bin/env sh
true --% ; : '
<#'


#
# sh part
#
echo "hello from bash/dash/zsh"
echo "do whatver you want just dont use #> directly"
echo "e.g. do #""> or something similar"
# end bash part

exit #>


#
# powershell part
#
echo "hello from powershell"
echo "you literally don't have to escape anything here"

如何? (其實很簡單)

語法高亮告訴我們幾乎整個故事

Powershell 突出顯示

檸檬綠色部分( ; : ' )只是參數
淡藍色很特別
<#是評論的開始在此處輸入圖片說明

Bash 突出顯示

對於 bash,它完全不同。
--%並不特殊,它只是一個參數( true忽略參數)
但是; 很特別,這就是命令的結尾
然后:實際上是“什么都不做”的shell命令
然后'開始一個在下一行結束的字符串參數
在此處輸入圖片說明

等等,它是如何工作的?

好吧,這要歸功於

  • Powershell停止解析arg( --% ),這讓我們不能在 powershell 中啟動字符串,而在 bash 中啟動字符串
  • Bash 的什么都不做的命令和多行引號
  • Powershell 的多行注釋<##>

注意事項?

幾乎沒有。 Powershell 合法地沒有缺點。 Bash 警告很容易修復,而且非常罕見

  1. 如果在 bash 字符串中需要 #>,則需要以某種方式對其進行轉義。
    "#>"更改為"#"">"
    或者從' blah #> '' blah #''> '
  2. 如果您有評論#>並且由於某種原因您不能更改該評論(這就是我所說的非常罕見的意思),您實際上可以只使用#> ,您只需要添加重新添加前兩行(例如true --%等)就在您的#>評論之后
  3. 一種更罕見的情況是您使用#刪除字符串的一部分(我敢打賭,大多數人甚至不知道這是一個 bash 功能)。 下面的示例代碼https://man7.org/linux/man-pages/man1/bash.1.html#EXPANSION
 var1=">blah" echo ${var1#>} # ^ removes the > from var1

為了解決這個問題,還有其他方法可以從字符串的開頭刪除字符,請改用它們。

跟進Jeff Hykin 的回答,我發現第一行雖然在 bash 中很開心,但在 PS 中產生了這個輸出。 請注意,它仍然功能齊全,只是嘈雜。

true : The term 'true' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling    
of the name, or if a path was included, verify that the path is correct and try again.
At C:\Users\jp\scratch\envar.ps1:4 char:1
+ true --% ; : '
+ ~~~~
    + CategoryInfo          : ObjectNotFound: (true:String) [], CommandNotFoundException
 
hello from powershell

我正在嘗試更改第一行:

true --% ; : '
<#'

到:

echo --% > /dev/null ; : ' | out-null
<#'

在非常有限的測試中,這似乎在 bash 和 powershell 中工作。 作為參考,我是在“采購”腳本而不是“調用”它們,例如. env.ps1 . env.ps1在 bash 和. ./env.ps1 . ./env.ps1在 powershell 中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM