是否可以编写一个在bash / shell和PowerShell中运行的脚本?

时间:2016-09-09 23:46:02

标签: linux windows bash shell powershell

我需要创建一个集成脚本来设置一些环境变量,使用wget下载文件并运行它。

挑战在于它需要是可以在Windows PowerShell和bash / shell上运行的SAME脚本。

这是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忽略错误,但没有成功。

任何猜测?

2 个答案:

答案 0 :(得分:7)

有可能;我不知道这是多么兼容,但PowerShell将字符串视为文本并最终显示在屏幕上,Bash将它们视为命令并尝试运行它们,并且都支持相同的函数定义语法。因此,将一个函数名称放在引号中,只有Bash会运行它,放入"退出"在引号中,只有Bash会退出。然后编写PowerShell代码。

NB。这是有效的,因为两个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

答案 1 :(得分:1)

虽然另一个答案很棒
(谢谢TessellatingHecklerHarry Johnston

我们实际上可以做得更好

  1. 使用更多 shell(例如为 Ubuntu 的 dash 工作)
  2. 在未来的情况下不太可能发生故障
  3. 无需浪费处理时间重新读取/评估脚本
  4. 在令人困惑的语法上浪费更少的字符/行
    (我们可以只用 26 个字符和 3 行)
  5. Even 保持语法高亮功能

复制粘贴代码

#!/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 突出显示

柠檬绿部分(; : ')只是参数
浅蓝色很特别
<# 是评论的开始 enter image description here

Bash 突出显示

对于 bash 来说完全不同。
--% 并不特殊,它只是一个参数(true 忽略参数)
但是 ; 是特殊的,这就是命令的结尾
那么:实际上就是“什么都不做”的shell命令
然后 ' 开始一个在下一行结束的字符串参数
enter image description here

等等,它是如何工作的?

很好,感谢

  • Powershell 的 stop parsing 参数(--%)让我们不用在 powershell 中开始一个字符串,而在 bash 中开始一个字符串
  • Bash 的什么都不做的命令和多行引号
  • Powershell 的多行注释 <##>

注意事项?

几乎没有。 Powershell 合法地没有缺点。 Bash 警告很容易修复,而且非常罕见

  1. 如果在 bash 字符串中需要 #>,则需要以某种方式对其进行转义。
    "#>" 更改为 "#"">"
    或从 ' blah #> ' 更改为 ' blah #''> '
  2. 如果您有一个评论 #> 并且由于某种原因您不能更改该评论(这就是我所说的非常罕见的意思),您实际上可以使用 #>,您只需要添加 re - 在您的 true --% 评论之后添加前两行(例如 #> 等)
  3. 一种更为罕见的情况是您使用 # 删除字符串的一部分(我敢打赌,大多数人甚至不知道这是一个 bash 功能)。下面的示例代码 https://man7.org/linux/man-pages/man1/bash.1.html#EXPANSION
var1=">blah"
echo ${var1#>}
# ^ removes the > from var1

要解决这个问题,还有其他方法可以从字符串的开头删除字符,请改用它们。