How to enter docker container use shell script and do something? - linux

I want to enter my container and do something, then leave this container.
#!/bin/bash
docker exec -i ubuntu-lgx bash << EOF
echo "test file" >> /inner.txt
ls -l /inner.txt
content=`cat /inner.txt`
echo ${conent}
# do something else
EOF
when I run this script, the bash tell me the file is not exist.but the ls can output the file's property.
cat: /inner.txt: No such file or directory
-rw-r--r--. 1 root root 58 Nov 14 11:51 /inner.txt
where am I wrong? and how to fix it?

The problem is that you're not protecting your "here" document from local shell expansion. When you write:
#!/bin/bash
docker exec -i ubuntu-lgx bash << EOF
content=`cat /inner.txt`
EOF
That cat /inner.txt is run on your local system, not the remote system. The contents of here document are parsed for variable expansion and other shell features.
To prevent that, write it like this:
#!/bin/bash
docker exec -i ubuntu-lgx bash << 'EOF'
echo "test file" >> /inner.txt
ls -l /inner.txt
content=`cat /inner.txt`
echo ${content}
# do something else
EOF
The single quotes in 'EOF' are a signal to the shell to interpret the here document verbatim.

Related

Define environment variable in a subshell with heredoc

Background: testing a bash script inside a pod where default user does not have sudo rights so that user cannot user vim or nano to create a .sh file so I have to find a way around with cat << EOF >> test.sh.
I am doing some local test to make sure it's working properly first. Locally I am creating a file test.sh with nano. See below
#!/bin/bash
# test.sh
VAR="Test"
echo $VAR
When I cat it:
#!/bin/bash
# test.sh
VAR="Test"
echo $VAR%
I save test.sh , made it execuatble chmod +x test.sh and ran it with ./test.sh The output:
Test
Now when I try to mimic the same behavior in a bash heredoc instead this is the command I use:
cat <<EOF >> test.sh
#!/bin/bash
# test.sh
VAR="Test"
echo $VAR
EOF
I saved it and made it execuatble as well. The cat output is:
#!/bin/bash
# test.sh
VAR="Test"
echo
So obviously running it wouldn't work. The output null.
I think the issue I am facing is that the environment variable $VAR is not defined properly inside the subshell using heredoc.
When you write this:
cat <<EOF >> test.sh
#!/bin/bash
# test.sh
VAR="Test"
echo $VAR
EOF
...that $VAR is expanded by your current shell (just like writing something like echo "$VAR"). If you want to suppress variable expansion inside your heredoc, you can quote it (note the quotes around 'EOF'):
cat <<'EOF' >> test.sh
#!/bin/bash
# test.sh
VAR="Test"
echo $VAR
EOF
This inhibits variable expansion just like single quotes (echo '$VAR').

Run ls command inside ssh

I have a script something like below
sshpass -p "pwd" ssh -tt user#host << EOF
cd /directory
file=$(ls -1t| head -1)
exit
EOF
cd /directory is changing the directory successfully inside shell. But ls gives the result which is outside the shell. The result of ls is same as when executed outside ssh. Please help in this.
The $(...) part is being evaluated by the outer shell. You can disable this by quoting 'EOF' so that $(...) is passed to the remote shell. It's akin to using single quotes instead of double quotes with regular strings.
sshpass -p "pwd" ssh -tt user#host << 'EOF'
cd /directory
file=$(ls -1t| head -1)
exit
EOF

Unable to use local and remote variables within a heredoc or command over SSH

Below is an example of a ssh script using a heredoc (the actual script is more complex). Is it possible to use both local and remote variables within an SSH heredoc or command?
FILE_NAME is set on the local server to be used on the remote server. REMOTE_PID is set when running on the remote server to be used on local server. FILE_NAME is recognised in script. REMOTE_PID is not set.
If EOF is changed to 'EOF', then REMOTE_PID is set and `FILE_NAME is not. I don't understand why this is?
Is there a way in which both REMOTE_PID and FILE_NAME can be recognised?
Version 2 of bash being used. The default remote login is cshell, local script is to be bash.
FILE_NAME=/example/pdi.dat
ssh user#host bash << EOF
# run script with output...
REMOTE_PID=$(cat $FILE_NAME)
echo $REMOTE_PID
EOF
echo $REMOTE_PID
You need to escape the $ sign if you don't want the variable to be expanded:
$ x=abc
$ bash <<EOF
> x=def
> echo $x # This expands x before sending it to bash. Bash will see only "echo abc"
> echo \$x # This lets bash perform the expansion. Bash will see "echo $x"
> EOF
abc
def
So in your case:
ssh user#host bash << EOF
# run script with output...
REMOTE_PID=$(cat $FILE_NAME)
echo \$REMOTE_PID
EOF
Or alternatively you can just use a herestring with single quotes:
$ x=abc
$ bash <<< '
> x=def
> echo $x # This will not expand, because we are inside single quotes
> '
def
remote_user_name=user
instance_ip=127.0.0.1
external=$(ls /home/)
ssh -T -i ${private_key} -l ${remote_user_name} ${instance_ip} << END
internal=\$(ls /home/)
echo "\${internal}"
echo "${external}"
END

cat in multiple ssh commands does not work

This is probably very basic but unfortunately I have no idea how to google it.
Why doesn't the snippet below work as expected? I mean, how can I make cat point to the remote file?
#!/bin/bash
ssh user#remoteaddress << EOF
mkdir sandpit
cd sandpit
echo "foo" > foo.txt
echo `cat foo.txt` > foo2.txt
EOF
Use it as:
ssh -t -t user#remoteaddress<<'EOF'
mkdir sandpit
cd sandpit
echo "foo" > foo.txt
cat foo.txt > foo2.txt
xargs kill < pid.txt
exit
EOF
Without quotes around starting EOF all words are subject to shell expansion and reverse quotes are expanded in your current shell not on ssh.

How to log non-interactive bash command sent through ssh

I'm sending a command through ssh:
ssh server.org 'bash -s' << EOF
ls -al
whoami
uptime
EOF
How to log it in the system (remote server)? I'd like to log those commands in some file (.bash_history or /tmp/log).
I've tried to add the line below to sshd_config:
ForceCommand if [[ -z $SSH_ORIGINAL_COMMAND ]]; then bash; else echo "$SSH_ORIGINAL_COMMAND" >> .bash_history; bash -c "$SSH_ORIGINAL_COMMAND"; fi
But it logs "bash -s" only.
I'll appreciate any help.
When bash shell exits, bash reads and executes commands from the ~/.bash_logout file. Probably you can run the history command at the end in the .bash_logout(of the server) and save it to some location.
If it suffices to work with the given command, we can put the necessary additions to enable and log command history at the beginning and end, e. g.
ssh server.org bash <<EOF
set -o history
ls -al
whoami
uptime
history|sed 's/ *[0-9]* *//' >>~/.bash_history
EOF
Or we could put them into the awfully long ForceCommand line:
… if [[ "$SSH_ORIGINAL_COMMAND" == bash* ]]; then echo "set -o history"; cat; echo "history|sed 's/ *[0-9]* *//' >>~/.bash_history"; else cat; fi | bash -c "$SSH_ORIGINAL_COMMAND"; fi

Resources