Executing Commands from Windows on Unix via Batchfile - bash

I have a problem that cannot find a solution for quite a while.
I want to execute following line from a Batch file on my windows machine:
ssh %1#%2 "D: && ssh %3#%4 cd /media/usbmsd/ && cp "$(ls -t /media/usbmsd | head -1)" /buffer"
THis batch file will be later executed from a cmd line with the parameters. I am trying to access one system (windows) via ssh and that hop again via ssh to the another system(unix) and there I need to find the newest file in the /media/usbmsd directory and copy it to the folder buffer.
When I excetuting it from my cmd line i am getting following error:
'head' is not recognized as an internal or external command,
operable program or batch file.
I have to say that I am not very experienced with this kind of application and am happy about any help
Greeting Denis

You could connect via a proxy jump, then you don't need a second ssh command.
Then a bit obscure escaping of the quotes is necessary.
(I tested this without the intermediate windows client)
The first caret ^ is necessary to quote from the cp command, the backslashes are necessary to convince the first expansion to leave the quotes untouched.
ssh %3#%4 -o ProxyJump %1#%2 ^"cd /media/usbmsd/ && cp \"$(ls -t /media/usbmsd | head -1)\" /buffer'
But it should be much easier to place a script on the destination host mycopyscript.sh
cd /media/usbmsd/ && cp "$(ls -t /media/usbmsd | head -1)" /buffer
And then use:
ssh %3#%4 -o ProxyJump %1#%2 "./mycopyscript.sh"

Related

Executing command remotely | Keep only 5 recent files/directories

I created a test directory on a remote server. To simulate this command, I created 6 files inside this test directory. The expected behavior of the command is to only keep 5 recent files in the directory. Good news is this command works!
My only trouble is I cannot execute the same command remotely. Only difference is the "" notation for the remote execution:
ssh account#someremoteserver.com "rm -rf `ls -t /usr/local/testingCommands | awk 'NR>5'`"
The reason for this is.. I have a Jenkins CI server that needs to remotely clean up the remote server, only keeping 5 most recent files.
Any help is greatly appreciated. Thanks!
ssh account#someremoteserver.com '/usr/bin/ls -1Qt /usr/local/testingCommands | awk "NR > 5" | /usr/bin/xargs /usr/bin/rm -rf'
Remarks:
Use absolute directory for all commands (security reasons)
rm ... $(...) really too dangerous, so invert rm and ls commands:
use ls command with one file per line option (-1), quoted filenames (-Q) for filenames with spaces

Copy files from a local to remote folder with scp and script throws "No such file or directory"

Description
I want to copy all files ending on .jpg from my local machine to the remote machine with scp.
For this i have a small "script". It looks like this:
#!/bin/bash
xfce4-terminal -e "scp -r -v /path/to/local/folder/*.jpg <user>#<IP>:/var/path/to/remote/folder/" --hold
Problem
When i open a terminal and enter scp -r -v /path/to/local/folder/*.jpg <user>#<IP>:/var/path/to/remote/directory/ it works.
So SSH is working correct.
When i start the script it doesnt.
The script works, when i copy the whole local folder. It then looks like this (simply the *.jpg is removed):
#!/bin/bash
xfce4-terminal -e "scp -r -v /path/to/local/folder/ <user>#<IP>:/var/path/to/remote/folder/" --hold
But then i have the local folder inside the remote folder, where i only want to have the files.
I dont know, if it is important but currently i use a computer with Linux Mint 19.3, xfce terminal and zshell.
Question
So how do i run a script correctly that copys files from a local folder to remote folder?
It's the shell who expands the wildcard, but when you run -e in xfce4-terminal, it runs the command without letting the shell parse it. You can run a shell to run the command, though:
xfce4-terminal -e "bash -c 'scp -r -v /path/to/local/folder/*.jpg user#ip:/var/path/to/remote'" --hold
Are you sure you need the -r? Directories are usually not named .jpg.

How to build script bash with SFTP connection to pull files

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

SSH command chain does not work when put in single line

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.

How to rename all files over SSH

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

Resources