できない.dev

PowerShell で && が使えない(トークン '&&' は、このバージョンでは有効なステートメント区切りではありません)

&&|| はパイプラインチェーン演算子で PowerShell 7 から追加された。
Windows PowerShell 5.1 では構文エラーになるため、;if ($?) に置き換えるか pwsh を使う。

公開:

要約

npm ci && npm run build のような bash 由来のコマンド列を貼り付けて次のエラーが出るのは、&& がそのバージョンの PowerShell に存在しないからである。

PS C:\work> npm ci && npm run build
トークン '&&' は、このバージョンでは有効なステートメント区切りではありません。
    + CategoryInfo          : ParserError: (:) []、ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidEndOfLine

&&||パイプラインチェーン演算子と呼ばれ、公式ドキュメント(新しいタブで開く)にあるとおり PowerShell 7 から実装された。
Windows に標準搭載されている Windows PowerShell 5.1 では構文エラーになる。

7 系(pwsh)に切り替えるのが素直な解決策で、5.1 に留まる必要があるなら ;if ($?) で同じ意味を書ける。

よくある原因

  1. 実行しているのが 5.1: $PSVersionTable.PSVersion5.1.x なら該当する。
    Windows に最初から入っている powershell.exe は 5.1 で、7 系は別途インストールする pwsh.exe である。
    両者は共存する。
  2. bash / cmd のコマンド列をそのまま貼った: && は POSIX シェルの AND-OR リストや cmd.exe の条件付き処理記号に相当する記法で、README の手順をそのまま持ち込むと踏む。
  3. CI が 5.1 を選んでいる: GitHub Actions の Windows ランナーでは shell: powershell が 5.1、shell: pwsh が 7 系を指す。
    手元の pwsh では通るのに CI だけ落ちる場合はここを疑う。
  4. パイプと混同している: && はオブジェクトを渡さない。
    左のパイプラインが成功したかどうかだけを見て右を実行する演算子である。

解決策

1. PowerShell 7 で実行する

pwsh -Command "npm ci && npm run build"

バージョンは次で確認する。

$PSVersionTable.PSVersion
Major  Minor  Patch  PreReleaseLabel BuildLabel
-----  -----  -----  --------------- ----------
7      5      0

2. 5.1 では ;if ($?) に書き換える

公式ドキュメントが示すとおり、パイプラインチェーン演算子は $? を使った条件分岐と等価である。

npm ci; if ($?) { npm run build }

|| に相当する「失敗したときだけ実行」はこう書く。

npm ci; if (-not $?) { Write-Error "install に失敗した" }

無条件に続けて実行したいだけなら ; だけでよい。&& を「単なる区切り」のつもりで使っていた場合は、; への置換で意図どおりになる。

3. CI ではシェルを明示する

- name: Build
  shell: pwsh
  run: npm ci && npm run build

shell: pwsh を書かないと Windows ランナーの既定シェルに引きずられる。
ワークフロー全体で揃えるなら defaults.run.shell に指定しておく。

4. 外部コマンドの成否判定に注意する

$? はネイティブコマンドの場合 $LASTEXITCODE を見て決まる。
終了コードを返さないコマンドや、エラーでも 0 を返すコマンドでは分岐が期待どおりに動かない。
その場合は終了コードを直接見る。

npm ci
if ($LASTEXITCODE -eq 0) { npm run build }

この記事は役立ちましたか?