If simple command substitution does not work right out of the box for you (which can happen), I'd consider - next to improving shell debugging skills - to get composers output more stable.
The one part I already placed as a comment, in shell scripts the following global arguments:
- use
-n to make composer non-interactive if that is the intended use. this keeps many issues out of the factory.
- use
--no-ansi to make composer not output ansi escape sequences (for coloring the output).
- use
--no-plugins to disable plugins, you want to keep those out as well in scripts.
In addition to those run-time-behaviour controlling arguments there is also one for the output. This is helpful if you want to ensure it is machine-readable. For example you can get the installed package names as JSON Text:
$ composer -n --no-plugins --format=json show --no-dev --name-only
{
"installed": [
{
"name": "composer/ca-bundle"
},
{
"name": "composer/metadata-minifier"
},
...
]
}
You can then use a utility to pipe the result into that is able to parse JSON Text and error out otherwise, e.g. jq(1) or php(1). Here an example w/ PHP (7.0+) as it is likely already available:
$ composer -n --no-plugins --format=json show --no-dev --name-only \
| php -r \
' echo implode("\n", array_column('\
' json_decode(stream_get_contents(STDIN))->installed, '\
' "name")) ?? exit(1), "\n";'
composer/ca-bundle
composer/metadata-minifier
...
This then is a good filter to further process the data in your script.
Do a strict validation of the composer.json before running any of such scripts as here you want to ensure that all package names are strictly conforming with the portable composer package name profile that is now in effect since a couple of releases (but I have no idea how deep it scans, otherwise pathchk(1) comes to mind).
Full example with some shell debugging and error handling:
#! /bin/sh
set -x
list_of_all_no_dev_package=$(
composer -nq --no-plugins validate --strict >&2 &&
composer -n --no-ansi --no-plugins --format=json show --no-dev --name-only |
php -r 'echo
implode($terminator = "\n",
array_column(
json_decode(stream_get_contents(STDIN))->installed,
"name"
)
) ?? exit(1),
$terminator
;
'
) || exit
for no_dev_package in $list_of_all_no_dev_package; do
printf "no dev package: '%s'\n" "${no_dev_package}" >&2
cp -r "vendor/${no_dev_package}" \
"${export_path?:export_path unset}/vendor/${no_dev_package}"
done
And if you consider to actually use /bin/bash check your bash version, there are arrays and you can read them in, compare shellharden etc..