cat in multiple ssh commands does not work - linux

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.

Related

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

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.

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

iterating through ls output is not occurring in bash

I am trying to ls the directories and print them out but nothing is being displayed. I am able to SSH and execute the first pwd. However, anything within the the for loop has no output. I know for sure there are directories called event-test- because I've done so manually. I've manually entered the directory (/data/kafka/tmp/kafka-logs/) and ran this piece of code and the correct output appeared so I'm not sure why
manually entered has correct output:
for i in `ls | grep "event-test"`; do echo $i; done;
script:
for h in ${hosts[*]}; do
ssh -i trinity-prod-keypair.pem bc2-user#$h << EOF
sudo bash
cd /data/kafka/tmp/kafka-logs/
pwd
for i in `ls | grep "event-test-"`; do
pwd
echo $i;
done;
exit;
exit;
EOF
done
It is because
`ls | grep "event-test-"`
is executing on your localhost not on remote host. Besides parsing ls is error prone and not even needed. You can do:
for h in "${hosts[#]}"; do
ssh -t -t trinity-prod-keypair.pem bc2-user#$h <<'EOF'
sudo bash
cd /data/kafka/tmp/kafka-logs/
pwd
for i in *event-test-*; do
pwd
echo "$i"
done
exit
exit
EOF
done
When parsing ls it is good practice to do ls -1 to get a prettier list to parse. Additionally, when trying to find files named "event-test-" I would recommend the find command. Since I am not completely sure what you are attempting to do other than list the locations of these "event-test" files I'd recommend something more similar to the following:
for h in "${hosts[#]}"; do ssh trinity-prod-keypair.pem bc2-user#$h -t -t "find /data/kafka/tmp/kafka-logs/ -type f -name *event-test-*;" ; done
This will give you a pretty output of the full path to the file and the file name.
I hope this helps.

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

how to run more than one command one terminal?

i have to run "for" loop on linux terminal itself how i can do.
ex.for i in cat ~/log;do grep -l "UnoRuby" $i >> ~/logName; done.
Just as you typed it should be fine except: for i in $(cat ~/log); do grep -l "UnoRuby" $i >> ~/logName; done
You should prefer < instead of cat, and a more friendly format for the quesiton:
for i in $(< ~/log)
do
grep -l "UnoRuby" $i >> ~/logName
done

Resources