Skip to content

Commit 0777da6

Browse files
authored
Merge pull request #8310 from v-thepet/pipelines9-5
Freshness: Pipelines 5
2 parents d8866e0 + ea540f7 commit 0777da6

File tree

1 file changed

+47
-74
lines changed

1 file changed

+47
-74
lines changed

docs/pipelines/scripts/cross-platform-scripting.md

Lines changed: 47 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,24 @@ title: Cross-platform scripting
33
description: Patterns for safe cross-platform scripting
44
ms.topic: conceptual
55
ms.assetid: 96b7da24-617e-4a58-b65f-040c374e60e2
6-
ms.date: 11/02/2023
6+
ms.date: 09/12/2025
77
monikerRange: '<= azure-devops'
8+
#customer intent: As an Azure Pipelines user, I want to understand how cross-platform scripting works so I can easily support different build platforms in my pipelines.
89
---
910

10-
# Run cross-platform scripts
11+
# Cross-platform scripting
1112

1213
[!INCLUDE [version-lt-eq-azure-devops](../../includes/version-lt-eq-azure-devops.md)]
1314

14-
With Azure Pipelines, you can run your builds on macOS, Linux, and Windows machines. If you develop on cross-platform technologies such as .NET Core, Node.js and Python, these capabilities bring both benefits and challenges.
15+
Azure Pipelines can run pipelines on Linux, macOS, and Windows machines. If you use cross-platform development technologies like .NET Core, Node.js, or Python, these cross-platform build capabilities bring both benefits and challenges. For example, most pipelines include one or more scripts to run during the build process, but script syntax often differs over platforms.
1516

16-
For example, most pipelines include one or more scripts that you want to run during the build process.
17-
But scripts often don't run the same way on different platforms. You can use the `script` keyword shortcut to make writing scripts easier and also can use conditions to target specific platforms with your scripts.
17+
This article explains how you can use cross-platform scripting to support different build platforms. You can use an Azure Pipelines `script` step to ease writing cross-platform scripts. You can also use [conditions](../process/conditions.md) to target scripts to specific platforms.
1818

19-
## Run cross-platform tools with a script step
19+
## Script step
2020

21-
The script keyword is a shortcut for the [command line task](/azure/devops/pipelines/tasks/reference/cmd-line-v2). The `script` keyword runs Bash on Linux and macOS and cmd.exe on Windows.
21+
The [script](../get-started/key-pipelines-concepts.md#scripts) keyword is a shortcut for the [command line task](/azure/devops/pipelines/tasks/reference/cmd-line-v2), which runs Bash on Linux and macOS or cmd.exe on Windows.
2222

23-
Using `script` can be useful when your task just passes arguments to a cross-platform tool. For instance, calling
24-
`npm` with a set of arguments can be easily accomplished with a `script` step.
25-
`script` runs in each platform's native script interpreter: Bash on macOS and Linux, cmd.exe on Windows.
23+
You can use `script` to easily pass arguments to a cross-platform tool. The `script` step runs in each platform's native script interpreter, Bash on macOS and Linux or cmd.exe on Windows. The following example uses a `script` step to call `npm` with a set of arguments.
2624

2725
#### [YAML](#tab/yaml/)
2826
```yaml
@@ -35,31 +33,29 @@ steps:
3533
#### [Classic](#tab/classic/)
3634
1. Add a **Command Line** task to your pipeline.
3735
38-
2. Replace the body of the script with:
36+
1. Replace the body of the script with:
3937
```
4038
npm install
4139
npm test
4240
```
4341

44-
* * *
45-
## Handle environment variables
42+
---
43+
44+
## Environment variables
45+
46+
Command line, PowerShell, and Bash resolve [environment variables](../process/variables.md#environment-variables) differently. To access a system-provided value like PATH, you must use a different syntax per platform.
4647

47-
Environment variables throw the first wrinkle into writing cross-platform scripts.
48-
Command line, PowerShell, and Bash each have different ways of reading environment variables.
49-
If you need to access an operating system-provided value like PATH, you'll need different techniques per platform.
48+
Azure Pipelines uses [macro syntax](../process/variables.md#macro-syntax-variables) as a cross-platform way to refer to variables at runtime. Variables with macro syntax get processed before a task executes during runtime. The variable expands before the platform shell encounters it.
5049

51-
However, Azure Pipelines offers a cross-platform way to refer to variables that
52-
it knows about called [macro syntax](../process/variables.md#understand-variable-syntax). By surrounding a variable name in `$( )`, it's expanded
53-
before the platform's shell ever sees it. For instance, if you want to echo out
54-
the ID of the pipeline, the following script is cross-platform friendly:
50+
To use macro syntax in a pipeline, surround the variable name as follows: `$(<variable name>)`. The following cross-platform example script echoes the ID of the pipeline.
5551

5652
#### [YAML](#tab/yaml/)
5753
```yaml
5854
steps:
5955
- script: echo This is pipeline $(System.DefinitionId)
6056
```
6157
62-
This also works for variables you specify in the pipeline.
58+
This syntax also works for variables you define within the pipeline.
6359
6460
```yaml
6561
variables:
@@ -72,22 +68,18 @@ steps:
7268
#### [Classic](#tab/classic/)
7369
1. Add a **Command Line** task to your pipeline.
7470
75-
2. Replace the body of the script with:
71+
1. Replace the body of the script with:
7672
```
7773
echo This is pipeline $(System.DefinitionId)
7874
```
7975

80-
* * *
81-
## Consider Bash or pwsh
76+
---
77+
78+
## Bash task
8279

83-
If you have more complex scripting needs than the examples shown above, then consider writing them in Bash.
84-
Most macOS and Linux agents have Bash as an available shell, and Windows agents include Git Bash or [Windows Subsystem for Linux](/windows/wsl/about) Bash.
85-
::: moniker range=">=azure-devops-2020"
86-
For Azure Pipelines, the Microsoft-hosted agents always have Bash available.
87-
::: moniker-end
80+
If you need more complex scripts, consider writing them in Bash and using the [Bash task](/azure/devops/pipelines/tasks/reference/bash-v3) in your pipeline. Most macOS and Linux agents use Bash as a shell, and Windows agents can use Git Bash or [Windows Subsystem for Linux](/windows/wsl/about) Bash. [Microsoft-hosted agents](../agents/hosted.md) have Bash preinstalled by default.
8881

89-
For example, if you need to make a decision about whether your build is triggered by a pull
90-
request:
82+
The following example runs a Bash task that helps make a decision about whether to trigger a build.
9183

9284
#### [YAML](#tab/yaml/)
9385
```yaml
@@ -110,10 +102,8 @@ steps:
110102
111103
#### [Classic](#tab/classic/)
112104
1. Add a **Bash** task to your pipeline.
113-
114-
2. For the **Type**, select Inline.
115-
116-
3. Replace the body of the script with:
105+
1. For **Type**, select **Inline**.
106+
1. Replace the body of the script with:
117107
```bash
118108
if [ -n "$SYSTEM_PULLREQUEST_PULLREQUESTNUMBER" ]; then
119109
echo This is for pull request $SYSTEM_PULLREQUEST_PULLREQUESTNUMBER
@@ -122,22 +112,16 @@ steps:
122112
fi
123113
```
124114

125-
* * *
126-
PowerShell Core (`pwsh`) is also an option.
127-
It requires each agent to have PowerShell Core installed.
115+
---
128116

129-
## Switch based on platform
117+
>[!NOTE]
118+
>PowerShell is also an option for scripts. The [`pwsh`](/azure/devops/pipelines/yaml-schema/steps-pwsh) shortcut runs PowerShell 7.x on macOS, Linux, or Windows. Agents must have PowerShell 7.x installed. [Microsoft-hosted agents](../agents/hosted.md) have PowerShell 7.x installed by default.
130119
131-
In general, we recommend that you avoid platform-specific scripts to avoid problems such as duplication of your pipeline logic. Duplication causes extra work and extra risk of bugs.
132-
However, if there's no way to avoid platform-specific scripting, then you can use a `condition` to detect what platform you're on.
120+
## Platform-based switching
133121

134-
For example, suppose that for some reason you need the IP address of the build
135-
agent.
136-
On Windows, `ipconfig` gets that information.
137-
On macOS, it's `ifconfig`.
138-
And on Ubuntu Linux, it's `ip addr`.
122+
Platform-specific scripting to duplicate pipeline logic causes extra work and increased error risk. But if you can't avoid platform-specific scripting, you can use [conditions](../process/conditions.md) to detect what platform you're on.
139123

140-
Set up the below pipeline, then try running it against agents on different platforms.
124+
For example, to get the IP address of the build agent, you must use `ifconfig` on macOS, `ip addr` on Ubuntu Linux, and the `Get-NetIPAddress` cmdlet on Windows PowerShell. The following pipeline gets that information from agents on different platforms by using conditions.
141125

142126
#### [YAML](#tab/yaml/)
143127
```yaml
@@ -161,61 +145,50 @@ steps:
161145
condition: eq( variables['Agent.OS'], 'Windows_NT' )
162146
displayName: Get IP on Windows
163147

164-
# now we use the value, no matter where we got it
148+
# use the value
165149
- script: |
166150
echo The IP address is $(IP_ADDR)
167151
```
168152
169153
#### [Classic](#tab/classic/)
170-
First, add a Linux script.
171-
172-
1. Add a **Bash** task to your pipeline.
173154
174-
2. Set the **Type** to Inline.
155+
Add the Linux script:
175156
176-
3. Replace the body of the script with:
157+
1. Add a **Bash** task to your pipeline.
158+
1. In the configuration, set the **Type** to **Inline**.
159+
1. Replace the body of the script with:
177160
```bash
178161
export IPADDR=$(ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/')
179162
echo ##vso[task.setvariable variable=IP_ADDR]$IPADDR
180163
```
164+
1. Expand **Control Options**, select **Custom conditions** for **Run this task**, and in the **Custom condition** field, enter `eq( variables['Agent.OS'], 'Linux' )`.
181165

182-
4. Change the value of **Run this task** to "Custom conditions".
183-
184-
5. In the **Custom condition** field that appears, enter "eq( variables['Agent.OS'], 'Linux' )".
185-
186-
Next, add a macOS script.
166+
Add the macOS script:
187167

188-
1. Repeat the above steps, but for the body of the script, enter:
168+
1. Repeat the preceding steps, but for the body of the script, enter:
189169
```bash
190170
export IPADDR=$(ifconfig | grep 'en0' -A3 | tail -n1 | awk '{print $2}')
191171
echo ##vso[task.setvariable variable=IP_ADDR]$IPADDR
192172
```
173+
1. Expand **Control Options**, select **Custom conditions** for **Run this task**, and in the **Custom condition** field, enter `eq( variables['Agent.OS'], 'Darwin' )`.
193174

194-
2. For the **Custom condition**, enter "eq( variables['Agent.OS'], 'Darwin' )".
195-
196-
Next, add a Windows script.
175+
Add the Windows script:
197176

198177
1. Add a **PowerShell** task to your pipeline.
199-
200-
2. Set the **Type** to Inline.
201-
202-
3. Replace the body of the script with:
178+
1. Set the **Type** to **Inline**.
179+
1. Replace the body of the script with:
203180
```powershell
204181
Set-Variable -Name IPADDR -Value (Get-NetIPAddress | ?{ $_.AddressFamily -eq "IPv4" -and !($_.IPAddress -match "169") -and !($_.IPaddress -match "127") }).IPAddress
205182
Write-Host ##vso[task.setvariable variable=IP_ADDR]$env:IPADDR
206183
```
184+
1. Expand **Control Options**, select **Custom conditions** for **Run this task**, and in the **Custom condition** field, enter `eq( variables['Agent.OS'], 'Windows_NT' )`.
207185

208-
4. Change the value of **Run this task** to "Custom conditions".
209-
210-
5. In the **Custom condition** field that appears, enter "eq( variables['Agent.OS'], 'Windows_NT' )".
211-
212-
Finally, add a task that uses the value, no matter how we got it.
186+
Add a task that uses the `IPADDR` value.
213187

214188
1. Add a **Command line** task to your pipeline.
215-
216-
2. Replace the body of the task with:
189+
1. Replace the body of the task with:
217190
```
218191
echo The IP address is $(IP_ADDR)
219192
```
220193

221-
* * *
194+
---

0 commit comments

Comments
 (0)