O operador $(...) , chamado substituição do comando , é aquele que se expande para a saída padrão de um comando livre de seus caracteres de nova linha.
Quando não está em lista e em contextos de lista, também está sujeito a split + glob ( split apenas em zsh ).
Por exemplo, se cmd outputs *:x\n\n e $IFS contiver : , $(cmd) expandiria para *:x e, no contexto da lista, seria dividido em * e x e * seria expandido para a lista de arquivos no diretório atual.
Então, normalmente:
cmd1 $(cmd2)
com o valor padrão de $IFS (espaço, tabulação e nova linha) destina-se a passar para cmd1 a lista de arquivos que correspondem à lista de padrões (espaço / guia / nova linha delimitada) gerados por cmd2 .
Aqui, dada a mensagem de erro emitida pelo cmd1 , parece que o seu cmd2 não produz nada ou apenas espaço, tabulação, caracteres de nova linha que resultam em nenhum argumento foi passado para cmd1 .
Então, você pode precisar cuidar desse caso especial primeiro, como:
set -- $(docker images -f dangling=true -q)
[ "$#" -eq 0 ] || docker rmi "$@"
Ou com o GNU ou FreeBSD xargs do:
docker images -f dangling=true -q |
xargs -r docker rmi
Isso também evitaria que as palavras produzidas por docker images fossem tratadas como padrões de arquivo. xargs espera uma lista delimitada em branco + nova linha de palavras que ela passa como argumento para o comando e também entende algumas formas de citações. Você queria passar um argumento para cada linha de entrada, você usaria (com GNU xargs ):
docker images -f dangling=true -q |
xargs -rd '\n' docker rmi