はじめに
以下のような&&で連結されたコマンドの2つめのコマンドに対してNODE_ENV=production
を適用したい、という状況があったのだが、当初想定している方法が利用できなかったので、試行錯誤した。
$ yarn && webpack --mode=production
なぜ2つ目のコマンドに環境変数を受け渡したいかというと、Webpackの設定ファイルwebpack.config.js内でprocess.env.NODE_ENV
としてNODE_ENV
環境変数を参照しているためであった。
一番簡単なのは以下のようにexport
を利用する方法だが、一時的に適用する方法が知りたかったので調査した。
$ export NODE_ENV=production
$ yarn && webpack --mode=production
検証環境
$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
以下のshellスクリプトを利用して、検証する。
$ cat hoge.sh
#!/bin/bash
echo "$1: $HOGE"
以下のようにコマンドを連結し、first/secondの後にHOGE
環境変数の値が両方表示されることを最終目標とする。
$ export HOGE=true
$ ./hoge.sh first && ./hoge.sh second
first: true
second: true
結論
2通り方法があるが、どちらもシェルでラップするという発想。
1. サブシェルを利用
$ (export HOGE=true; ./hoge.sh first && ./hoge.sh second)
first: true
second: true
$ echo $HOGE
※出力なし(カレントシェルには影響を与えていない)
2. bash/zshの-c
オプションを利用
$ HOGE=true bash -c './hoge.sh first && ./hoge.sh second'
first: true
second: true
$ echo $HOGE
※出力なし(カレントシェルには影響を与えていない)
検証過程
参考までに結論に到るまでの検証過程を以下に示す。
まずはじめに思いついたのは、一時的に環境変数をコマンドに適用する方法。
調べてみると、この実行方法はパラメータとして指定するというものらしい。
$ HOGE=true ./hoge.sh first
first: true
しかし、&&で連結すると、2つ目のコマンドにはパラメータとして設定できていない。
$ HOGE=true ./hoge.sh first && ./hoge.sh second
first: true
second:
指定するにはそれぞれのコマンドに対して指定する必要があった。
$ HOGE=true ./hoge.sh first && HOGE=true ./hoge.sh second
first: true
second: true
いや、でもコマンドをまとめる方法もあるよね、と思って以下を実行すると
$ HOGE=true (./hoge.sh first && ./hoge.sh second)
bash: syntax error near unexpected token `('
シンタックスエラーだった。
という過程を経て、シェルでラップする方法にたどり着いた。
おまけ
検証方法を検討する中で、わざわざhoge.sh
使わなくてもいいかなと思って以下のコマンドを考えた。
$ HOGE=true echo "first: ${HOGE}" && echo "second: ${HOGE}"
first:
second:
が、予想に反してfirst: true
が表示されなかった。
よくよく考えるとパラメータとしてコマンドに環境変数を設定する方法だと、カレントシェルにはHOGE
環境変数が定義されていないことになる為。失敗ではあるが、仕組みがわかって面白い。
参考
Bashのmanページ
$ man bash
BASH(1) BASH(1)
NAME
bash - GNU Bourne-Again SHell
SYNOPSIS
bash [options] [file]
COPYRIGHT
Bash is Copyright (C) 1989-2005 by the Free Software Foundation, Inc.
DESCRIPTION
Bash is an sh-compatible command language interpreter that executes commands read from the standard input or from a file. Bash also incorporates useful features from the Korn and C shells (ksh and csh).
Bash is intended to be a conformant implementation of the Shell and Utilities portion of the IEEE POSIX specification (IEEE Standard 1003.1). Bash can be configured to be POSIX-conformant by default.
…
SHELL GRAMMAR
…
Lists
A list is a sequence of one or more pipelines separated by one of the operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or <newline>.
Of these list operators, && and || have equal precedence, followed by ; and &, which have equal precedence.
A sequence of one or more newlines may appear in a list instead of a semicolon to delimit commands.
If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0. Commands separated by a ; are
executed sequentially; the shell waits for each command to terminate in turn. The return status is the exit status of the last command executed.
The control operators && and || denote AND lists and OR lists, respectively. An AND list has the form
command1 && command2
command2 is executed if, and only if, command1 returns an exit status of zero.
An OR list has the form
command1 || command2
command2 is executed if and only if command1 returns a non-zero exit status. The return status of AND and OR lists is the exit status of the last command executed in the list.
Compound Commands
A compound command is one of the following:
(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The
return status is the exit status of list.
…
PARAMETERS
A parameter is an entity that stores values. It can be a name, a number, or one of the special characters listed below under Special Parameters. A variable is a parameter denoted by a name. A variable has a value and zero or
more attributes. Attributes are assigned using the declare builtin command (see declare below in SHELL BUILTIN COMMANDS).
A parameter is set if it has been assigned a value. The null string is a valid value. Once a variable is set, it may be unset only by using the unset builtin command (see SHELL BUILTIN COMMANDS below).
A variable may be assigned to by a statement of the form
name=[value]
If value is not given, the variable is assigned the null string. All values undergo tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, and quote removal (see EXPANSION below). If the
variable has its integer attribute set, then value is evaluated as an arithmetic expression even if the $((...)) expansion is not used (see Arithmetic Expansion below). Word splitting is not performed, with the exception of "$@"
as explained below under Special Parameters. Pathname expansion is not performed. Assignment statements may also appear as arguments to the alias, declare, typeset, export, readonly, and local builtin commands.
In the context where an assignment statement is assigning a value to a shell variable or array index, the += operator can be used to append to or add to the variable's previous value. When += is applied to a variable for which the
integer attribute has been set, value is evaluated as an arithmetic expression and added to the variable's current value, which is also evaluated. When += is applied to an array variable using compound assignment (see Arrays
below), the variable's value is not unset (as it is when using =), and new values are appended to the array beginning at one greater than the array's maximum index. When applied to a string-valued variable, value is expanded and
appended to the variable's value.
…
ENVIRONMENT
When a program is invoked it is given an array of strings called the environment. This is a list of name-value pairs, of the form name=value.
The shell provides several ways to manipulate the environment. On invocation, the shell scans its own environment and creates a parameter for each name found, automatically marking it for export to child processes. Executed com-
mands inherit the environment. The export and declare -x commands allow parameters and functions to be added to and deleted from the environment. If the value of a parameter in the environment is modified, the new value becomes
part of the environment, replacing the old. The environment inherited by any executed command consists of the shell's initial environment, whose values may be modified in the shell, less any pairs removed by the unset command,
plus any additions via the export and declare -x commands.
The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described above in PARAMETERS. These assignment statements affect only the environment seen by that
command.
If the -k option is set (see the set builtin command below), then all parameter assignments are placed in the environment for a command, not just those that precede the command name.
When bash invokes an external command, the variable _ is set to the full file name of the command and passed to that command in its environment.