My script is executing the following line:
ssh $REMOTE_USER#${SUPPORTED_SERVERS[$i]} "gtar -zcvf $TAR_FILE `find $LOCAL_PATH -name *$DATE*`
Now, the problem is that find command is being executed on the local machine and I need it to be executed on the remote one.
Please help,
Thanks
Use $() rather than backtick ` and additionaly escape it with backslash to avoid executing the command on the local machine:
ssh $REMOTE_USER#${SUPPORTED_SERVERS[$i]} "gtar -zcvf $TAR_FILE \$(find $LOCAL_PATH -name *$DATE*)"
Make a script, copy it to the server and run that. It may seem pointless now for such a simple thing, but you'll probably thank me later.
When executing a command over SSH, you need to escape any special characters that should not be evaluated locally. Escape the backticks to have them evaluated on the remote server:
ssh $REMOTE_USER#${SUPPORTED_SERVERS[$i]} "gtar -zcvf $TAR_FILE \`find $LOCAL_PATH -name *$DATE*\`
Assuming $TAR_FILE, $LOCAL_PATH and $DATE are local variables, otherwise escape them also. (They would need to exist as environment variables on the remote server)
Alternative
Like #RobinGreen points out: It is often better to make a script on the remote server and execute that over SSH.
#!/bin/sh
# This is the remote script
# Use positional arguments $1 - $3 and make a tarball
gtar -zcvf $1 $(find $2) -name "*$3*"
Call it like this
ssh $REMOTE_USER#${SUPPORTED_SERVERS[$i]} "/path/to/remote/script $TAR_FILE $LOCAL_PATH $DATE"
Related
I'm implementing agent script bash to pull files from the remote server with SFTP service.
The script must:
connect SFTP
file listing
cycling on files found
get every file and copy agent side
after that files copied must be deleted
The script is followed:
#!/bin/bash
SFTP_CONNECTION="sftp -oIdentityFile=/home/account_xxx/.ssh/service_ssh user#host"
DEST_DATA=/tmp/test/data/
# GET list file by ls command ###############
$SFTP_CONNECTION
$LIST_FILES_DATA_OSM1 = $("ls fromvan/test/data/test_1")
echo $LIST_FILES_DATA_OSM1
for file in "${LIST_FILES_DATA_OSM1[#]}"
do
$SFTP_CONNECTION get $file $DEST_DATA
$SFTP_CONNECTION rm $file
done
I tried the script but it seems that the connection and command execution (ls) are distinct on thread separated.
How can I provide command sequential as described above ?
Screenshoot:
Invalid find command
SSH it seem not available
RSYNC result to take the files is the followed:
Thanks
First of all, I would recommend the following syntax changes:
#!/bin/bash
sftp_connection() {
sftp -oIdentityFile=/home/account_xxx/.ssh/service_ssh user#host "$#";
}
Dest_Data=/tmp/test/data/
# GET list file by ls command ###############
sftp_connection
List_Files_D_OSM1=$("ls fromvan/test/data/test_1")
echo "$LIST_FILES_DATA_OSM1"
for file in "${LIST_FILES_DATA_OSM1[#]}"
do
sftp_connection get "$file" $Dest_Data
sftp_connection rm "$file"
done
Quoting $file and $List_Files_D_OSM1 to prevent globbing and word splitting.
Assignments can't start with a $, otherwise bash will try to execute List_Files_D_OSM1 and will complain with a command not found
No white spaces in assignments like List_Files_D_OSM1 = $("ls fromvan/test/data/test_1")
You can use ShellCheck to catch this kind of errors.
Having said that, it is in general not a good idea to use ls in such way.
What you can use instead is something like find. For example:
find . -type d -exec echo '{}' \;
Use a different client. lftp supports sftp as a transport, and has a subcommand for mirroring which will do the work of listing the remote directory and iterating over files for you.
Assuming your ~/.ssh/config contains an entry like:
Host myhost
IdentityFile /home/account_xxx/.ssh/service_ssh
...you can run:
lftp -e 'mirror -R fromvan/test/data/test_1 /tmp/test/data' sftp://user#myhost
I have the following chain of commands which work perfectly well:
ssh Module
cd /MODULE_DIR/workspace/repository/
LATEST=`ls -tr *.snapshot | head -1`
mkdir fresh
cp ${LATEST} fresh
exit
I want to put this into a bash script:
ssh Module "cd /MODULE_DIR/workspace/repository/ && LATEST=`ls -tr *.snapshot | head -1` && mkdir fresh && cp \${LATEST} fresh"
But it outputs error:
ls: cannot access '*.snapshot': No such file or directory
cp: missing destination file operand after 'fresh'
Try 'cp --help' for more information.
What am I missing here?
Try using single quotes instead of double-quotes on your SSH command.
Bash's order of expansions is going to try to expand those variables inside the double quotes based on the variable assignments on the computer you're running it on.
The variables in your command are likely blank locally; you can test this by adding an echo before the first quote and have the server echo back what command it's receiving.
Wrapping it in a single quote should make your local terminal not try to expand that variable and let the box you're connecting to handle it.
I am trying to rename all files in a remote directory over SSH or SFTP. The rename should convert the file into a date extension, for example .txt into .txt.2016-05-25.
I have the following command to loop each .txt file and try to rename, but am getting an error:
ssh $user#$server "for FILENAME in $srcFolder/*.txt; do mv $FILENAME $FILENAME.$DATE; done"
The error I am getting is:
mv: missing destination file operand after `.20160525_1336'
I have also tried this over SFTP with no such luck. Any help would be appreciated!
You need to escape (or single-quote) the $ of variables in the remote shell. It's also recommended to quote variables that represent file paths:
ssh $user#$server "for FILENAME in '$srcFolder'/*.txt; do mv \"\$FILENAME\" \"\$FILENAME.$DATE\"; done"
Try this:
By using rename (perl tool):
ssh user#host /bin/sh <<<$'
rename \047use POSIX;s/$/strftime(".%F",localtime())/e\047 "'"$srcFolder\"/*.txt"
To prepare/validate your command line, replace ssh...bin/sh by cat:
cat <<<$'
rename \047use POSIX;s/$/strftime(".%F",localtime())/e\047 "'"$srcFolder\"/*.txt"
will render something like:
rename 'use POSIX;s/$/strftime(".%F",localtime())/e' "/tmp/test dir"/*.txt
And you could localy try (ensuring $srcFolder contain a path to a local test folder):
/bin/sh <<<$'
rename \047use POSIX;s/$/strftime(".%F",localtime())/e\047 "'"$srcFolder\"/*.txt"
Copy of your own syntax:
ssh $user#$server /bin/sh <<<'for FILENAME in "'"$srcFolder"'"/*.txt; do
mv "$FILENAME" "$FILENAME.'$DATE'";
done'
Again, you could locally test your inline script:
sh <<<'for FILENAME in "'"$srcFolder"'"/*.txt; do
mv "$FILENAME" "$FILENAME.'$DATE'";
done'
or preview by replacing sh by cat.
When using/sending variables over SSH, you need to be careful what is a local variable and which is a remote variable. Remote variables must be escaped; otherwise they will be interpreted locally versus remotely as you intended. Other characters also need to be escaped such as backticks. The example below should point you in the right direction:
Incorrect
user#host1:/home:> ssh user#host2 "var=`hostname`; echo \$var"
host1
Correct
user#host1:/home:> ssh user#host2 "var=\`hostname\`; echo \$var"
host2
I have a script which sync's a few files with a remote host. The commands that I want to issue are of the form
rsync -avz ~/.alias user#y:~/.alias
My script looks like this:
files=(~/.alias ~/.vimrc)
for file in "${files[#]}"; do
rsync -avz "${file}" "user#server:${file}"
done
But the ~ always gets expanded and in fact I invoke the command
rsync -avz /home/user/.alias user#server:/home/user/.alias
instead of the one above. But the path to the home directory is not necessarily the same locally as it is on the server. I can use e.g. sed to replace this part, but it get's extremely tedious to do this for several servers with all different paths. Is there a way to use ~ without it getting expanded during the runtime of the script, but still rsync understands that the home directory is meant by ~?
files=(~/.alias ~/.vimrc)
The paths are already expanded at this point. If you don't want that, escape them or quote them.
files=('~/.alias' \~/.vimrc)
Of course, then you can't use them, because you prevented the shell from expanding '~':
~/.alias: No such file or directory
You can expand the tilde later in the command using eval (always try to avoid eval though!) or a simple substitution:
for file in "${files[#]}"; do
rsync -avz "${file/#\~/$HOME/}" "user#server:${file}"
done
You don't need to loop, you can just do:
rsync -avz ~/.alias/* 'user#y:~/.alias/'
EDIT: You can do:
files=(.alias .vimrc)
for file in "${files[#]}"; do
rsync -avz ~/"${file}" 'user#server:~/'"${file}"
done
I am writing a shell script and I need to SSH into a server, perform some actions, and then exit.
To do this, I am using code such as below:
ssh -t username#server '
cd uploads/; \
tar -xvzf torrent.tar.gz; \
'
However, I need to use a variable like so:
DIR="uploads/";
ssh -t username#server '
cd $DIR; \
tar -xvzf torrent.tar.gz; \
'
This doesn't seem to work because obviously the cd isn't being executed until the SSH connection is made, and by then there is no $DIR variable (my guess). However, is there any way I could use a variable?
Perhaps a better question is, is there a better way I could lay out my script to perform actions once the SSH connection is made? I am having to be careful, escaping apostrophes, and at one point I am actually SSHing to another server from inside an SSH connection. This is ugly code!
Edit: Just read that if I use " instead of ', the variable will work. However my question still stands about formatting?
Use double quotes to allow expansion. e.g. try this:
echo "$DIR"
vs
echo '$DIR'
and note the result.
It's worth wrapping this in a shell script thus:
#!/bin/bash -x
# ...
and the -x will output shell expansions etc. It makes life very easy for debugging.
Rather than using the above means to feed in commands, you can use a heredoc. e.g.
ssh username#host <<EOF
ls
EOF
will execute 'ls' on the remote host.
instead of single quotes (') why don't you use double quotes (") then the $DIR should be expanded
i think you have to write :
ssh username#server "( cd $DIR; tar -xvzf torrent.tar.gz; )"
this should execute after connection..
if not try with (" instead of "( and obviusly then close