I'm using SCP command to copy files using a bash script. How do I echo the file names that were copied successfully?
Use $? to access the return value of the last command. Check the man page for scp to verify, but I think a return value of zero means success. A non-zero value means some kind of failure.
scp "fromHere" hostname:"toThere"
if [ "$?" -eq "0" ];
then
echo "SUCCESS"
else
echo "FAIL"
fi
OR
for gzfile in $LOCALDMPDIR/*.gz
do
/usr/bin/scp -P 2222 -i $KEYFILE $gzfile foobar#$1:$TGTDIR 2>>/var/log/scperror.log \
&& echo "$gzfile is done." \
|| echo "scp error: $gzfile"
done
Related
I am writing my codes on gedit and I want to get the latest error and warning messages using if statement, if theres an error then I should get a warning messages.
cp /Volumes/Documents/criticalfile.txt /Volumes/BackUp/.
if [ "?" != 0 ]; then
echo "[Error] copy failed!" 1>&2
exit 1
fi
I've used the above code but I am not sure if its correct or not.
You have to use
if [ "$?" != 0 ]; then
instead of
if [ "?" != 0 ]; then
Let say I want to copy a file but i don't know if I will get an error. I use the below command
cp -f /root/Desktop/my_new_file */root/t
definitely this will give me an error because copying to "*/root/t" is not possible.
I can check this by using the following codes
#!/bin/bash
cp -f /root/Desktop/my_new_file */root/t
if [ "$?" = 0 ];then
echo "No error"
else
echo "We have error!"
fi
MY OUTPUT (Note the condition is working)
cp: cannot create regular file `*/root/t': No such file or directory
We have error
Now let say I want to copy a file to a possible location like
cp -f /root/Desktop/my_new_file /root/t
I will get no error from cp command
OUTPUT
No error
No, if [ "?" != 0 ] is not correct.
You're looking for if [ $? != 0 ] instead.
But an even better way:
if ! cp /Volumes/Documents/criticalfile.txt /Volumes/BackUp/
then
echo "[Error] copy failed!" >&2
exit 1
fi
I also dropped the 1 from 1>&2, as >&2 is the same thing.
fix your code.
cp /Volumes/Documents/criticalfile.txt /Volumes/BackUp/ > /dev/null 2>&1
if [ "$?" != 0 ]; then
echo "[Error] copy failed!"
exit 1
fi
one liner
cp infile /Volumes/BackUp/ > /dev/null 2>&1 || echo "[Error] copy failed!"
I am running a function in bash comparing two files $SRC and $DEST, I'm verifying that the command worked. Here is my working function. However if I remove the echo " " then it returns unsuccessful even if it worked. If I keep it in, it adds an extra blank output line and is successful. I've tried the following:
if [[ cmp -s "$SRC" "$DEST" >/dev/null 2>&1 ]]
and that returns errors. Any ideas?
copysuccess()
{
#Variable to track command
local COM=$1
if cmp -s "$SRC" "$DEST" >/dev/null 2>&1
echo " "
then
echo "$COM was successful"
else
echo "$COM was unsuccessful"
fi
}
Update:
Tried the following codes and now it outputs
cmp: file: is a directory.
I should have noted that this was for files AND directories. Sorry.
Also if I do a move directory where it is an overwrite, it outputs nothing.
Does not work:
cmp -s "$SRC" "$DEST"; [[ "$?" = 0 ]] && echo "$COM was successful" || echo "$COM was unsuccessful"
Does not work:
cmp -s "$SRC" "$DEST" && echo "$COM was successful" || echo "$COM was unsuccessful"
You should check return value of the executed command instead of the current approach. This is how I would've done it :
cmp -s "$SRC" "$DEST" >/dev/null 2>&1 && echo "success" || echo "failure"
Since -s option blocks all outputs, the rest can be removed.
Ended up going with Jdamian's advice and using $?
I created a global that got reset every time a major function was entered, and when I got the the copy portion
cp -f $SRC $DEST
TEST=$?
Was added. Then
copysuccess()
{
#Variable to track command
local COM=$1
if [[ $TEST == 0 ]]
then
echo "$COM was successful"
else
echo "$COM was unsuccessful"
fi
}
was the best option, I basically wanted to verify that the command ran successfully, which I wasn't clear on, and wanted to verify the copy worked, to bad my way was asinine and didn't know about the $?
I have a created a bash script which touches a file in specific mounts to monitor for directory locks or storage issues. I've done this using multiple if statements, but if I use the below syntax using exit at the end of the if then this exits the full script and not continue with checking the rest of the server hosts. Can someone tell me if there's either a better way of doing this or if I can replace the exit so that the script continues with the rest of the if statements?
ssh $SERVER1 touch /apps/mount/im.alive.txt
if [ $? -ne 0 ]; then
echo "$SERVER1 is in accessible. Please escalate"
else
exit
fi
ssh $SERVER2 touch /apps/mount/im.alive.txt
if [ $? -ne 0 ]; then
echo "$SERVER2 is in accessible. Please escalate"
else
exit
fi
To elaborate on the comment by #Mighty Portk: the else part of the if statement is not mandatory, so you can just get away without it, and without the exit:
ssh $SERVER1 touch /apps/mount/im.alive.txt
if [ $? -ne 0 ]; then
echo "$SERVER1 is in accessible. Please escalate"
fi
ssh $SERVER2 touch /apps/mount/im.alive.txt
if [ $? -ne 0 ]; then
echo "$SERVER2 is in accessible. Please escalate"
fi
Or just simplify it like this:
ssh "$SERVER1" touch /apps/mount/im.alive.txt || \
echo "$SERVER1 is in accessible. Please escalate"
ssh "$SERVER2" touch /apps/mount/im.alive.txt || \
echo "$SERVER2 is in accessible. Please escalate"
Or
for S in "$SERVER1" "$SERVER2"; do
ssh "$S" touch /apps/mount/im.alive.txt || \
echo "$S is in accessible. Please escalate."
done
You can also turn it into a script:
#!/bin/sh
for S; do
ssh "$S" touch /apps/mount/im.alive.txt || \
echo "$S is in accessible. Please escalate."
done
Usage:
sh script.sh "$SERVER1" "$SERVER2"
You don't have to run "ssh" and then explicitly test its exit code. The "if" command will do that for you. This is how I would write that:
if ssh $SERVER1 touch /apps/mount/im.alive.txt
then
true # do-nothing command
else
echo "$SERVER1 is in accessible. Please escalate"
fi
if ssh $SERVER2 touch /apps/mount/im.alive.txt
then
true # do-nothing command
else
echo "$SERVER2 is in accessible. Please escalate"
fi
However, since you're performing the same set of operations on more than one SERVER, you could use a loop:
for server in $SERVER1 $SERVER2
do
if ssh $server touch /apps/mount/im.alive.txt
then
true # do-nothing command
else
echo "$server is in accessible. Please escalate"
fi
done
And finally, (after all good recommendations) it is a good practice using functions for some actions, like error messages and such. Therefore, the
#put this at the top of your script
eecho() {
echo "Error: $#" >&2
return 1
}
will function as an echo, but always write the error message to STDERR, and returns problem (non zero status) so you can do the next:
[[ some_condition ]] || eecho "some error message" || exit 1
e.g. chain it with exit. (see konsolebox's recommendation)
the more I learn bash the more questions I have, and the more I understand why very few people do bash. Easy is something else, but I like it.
I have managed to figure out how to test directories and there writablity, but have a problem the minute I try to do this with a remote server over ssh. The first instance testing the /tmp directory works fine, but when the second part is called, I get line 0: [: missing]'`
Now if I replace the \" with a single quote, it works, but I thought that single quotes turn of variable referencing ?? Can someone explain this to me please ? Assuming that the tmp directory does exist and is writable, here the script so far
#!/bin/bash
SshHost="hostname"
SshRsa="~/.ssh/id_rsa"
SshUser="user"
SshPort="22"
Base="/tmp"
Sub="one space/another space"
BaseBashExist="bash -c \"[ -d \"$Base\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseBashExist} )
echo -n $Base
if [ $? -eq 0 ]
then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
BaseBashPerm="bash -c \"[ -w \"$Base\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseBashPerm} )
if [ $? -eq 0 ]
then
echo "...writeable"
else
echo "...not writeable"
fi
BaseAndSub="$Base/$Sub"
BaseAndSubBashExist="bash -c \"[ -d \"$BaseAndSub\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseAndSubExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseAndSubBashExist} )
echo -n $BaseAndSub
if [ $? -eq 0 ]
then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
BaseAndSubBashPerm="bash -c \"[ -w \"$BaseAndSub\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseAndSubPerm=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseAndSubBashPerm} )
if [ $? -eq 0 ]
then
echo -n "...writeable"
else
echo "...not writeable"
fi
exit 0
The first thing you should do is refactor your code with simplicity in mind, then the quoting error will go away as well. Try:
if ssh [flags] test -w "'$file'"; then
Encapsulate your SSH flags in a ssh config to facilitate re-use, and your script will shorten dramatically.
You are fine with single quotes in this context; by the time the script is seen by the remote bash, your local bash has already substituted in the variables you want to substitute.
However, your script is a total mess. You should put the repetitive code in functions if you cannot drastically simplify it.
#!/bin/bash
remote () {
# most of the parameters here are at their default values;
# why do you feel you need to specify them?
#ssh -l "user" -i ~/.ssh/id_rsa -p 22 hostname "$#"
ssh hostname "$#"
# —---------^
# if you really actually need to wrap the remote
# commands in bash -c "..." then add that here
}
exists_and_writable () {
echo -n "$1"
if remote test -d "$1"; then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
if remote test -w "$1"; then
echo "...writeable"
else
echo "...not writeable"
fi
}
Base="/tmp"
# Note the need for additional quoting here
Sub="one\\ space/another\\ space"
exists_and_writable "$Base"
BaseAndSub="$Base/$Sub"
exist_and_writable "$BaseAndSub"
exit 0
ssh -qnx "useraccount#hostname"
"test -f ${file absolute path} ||
echo ${file absolute path} no such file or directory"
Need some shell scripting help, especially with my if-then-else logic. I want to combine both conditions, but not sure if the file checks will work the same? Should I be doing something like a nested if?? My script uses the if statements to do file checks to see if they exist, then do something..
There is probably a better way to do file checks part too.
Any help, critique would be appreciated. Thanks.
Here's my code, it sort of works.
if [ $# != 1 ]; then
echo "Usage: getlogs.sh <remote-host>" 2>&1
exit 1
fi
#Declare variables
STAMP=`date '+%Y%m%d-%H:%M'`
REMOTE_MYCNF=/var/log/mysoft/mysoft.log
REMOTE_GZ=/var/log/mysoft/mysoft.log.1.gz
REMOTE_DIR=/var/log/mysoft/
BACKUP_DIR=/home/mysql/dev/logs/
NEWLOG="foo-temp.log"
export REMOTE_MYCNF STAMP SHORTNAME
export REMOTE_DIR REMOTE_GZ
#Copy file over
echo "START..." 2>&1
test -f $BACKUP_DIR$1.mysoft.log
if [ $? = 0 ]; then
echo "Local log file exists, clean up for new copy..." 2>&1
/bin/rm $BACKUP_DIR$1.mysoft.log
exit 0
else
echo "File does not exist, getting a new copy..." 2>&1
fi
echo "Checking remotely in $1 for foo logfile $REMOTE_MYCNF $STAMP" 2>&1
if [ ! -f $REMOTE_MYCNF ]; then
echo "File exists remotely, creating new logfile and copy here...." 2>&1
ssh $1 "zcat $REMOTE_GZ >> $REMOTE_DIR$NEWLOG"
ssh $1 "cat $REMOTE_MYCNF >> $REMOTE_DIR$NEWLOG"
/usr/bin/scp $1:$REMOTE_DIR$NEWLOG $BACKUP_DIR$1.mysoft.log
echo "end remote copy" 2>&1
echo "Cleaning up remote files" 2>&1
ssh $1 "rm $REMOTE_DIR$NEWLOG"
exit 0
else
echo "Unable to get file" 2>&1
exit 0
fi
Updated code using help:
if [ -f $BACKUP_DIR$1.mysoft.log ]; then
echo "Local log file exists, clean up for new copy..." 2>&1
/bin/rm $BACKUP_DIR$1.mysoft.log
exit 0
else
echo "File does not exist, getting a new copy..." 2>&1
echo "Checking remotely in $1 for foo logfile $REMOTE_MYCNF $STAMP" 2>&1
if [ ! -f $REMOTE_MYCNF ]; then
echo "File exists remotely, creating new logfile and bring a copy here...." 2>&1
ssh $1 "zcat $REMOTE_GZ >> $REMOTE_DIR$NEWLOG"
ssh $1 "cat $REMOTE_MYCNF >> $REMOTE_DIR$NEWLOG"
/usr/bin/scp $1:$REMOTE_DIR$NEWLOG $BACKUP_DIR$1.mysoft.log
echo "end remote copy" 2>&1
echo "Cleaning up remote files" 2>&1
ssh $1 "rm $REMOTE_DIR$NEWLOG"
exit 0
else
echo "Unable to get file" 2>&1
exit 0
fi
fi
The file test can be combined into one statement like this:
if [ -f $BACKUP_DIR$1.mysoft.log ]; then
At a glance, it doesn't look like you need to export any of the variables.
If you intend for the if [ ! -f $REMOTE_MYCNF ]; then block to be executed within the else of the previous if, just move it within it.
if ...
then
foo
else
if ...
then
bar
else
baz
fi
fi
If you need to check two things:
if [ "$foo" = "bar" && "$baz" = "qux" ]
Always quote your variables.
In a short script it's fine to use positional parameters such as $1 directly, but it makes a longer script easier to understand if a variables with meaningful names are assigned their values near the top.
remote_host=$1
When you want to echo errors to stderr do it this way:
echo "Message" >&2
The way you have it, you're echoing the message and any errors the echo itself may produce (pretty rare) to stdout.