Source bash from url only if file from the url exists and hide output - bash

I've been searching the web but couldn't find the answer for my situation. I believe it's a first?
Anyway, here's what I'm trying to do;
#!/bin/bash
if source <(curl -s -f http://example.com/$1.txt); then
echo "Found the file"
else
echo "Couldn't find it"
fi
This is supposed to source the bash from http://example.com/$1.txt when I run the script like this; ./myscript.sh fileName while hiding any success of error outputs because I don't want them to show up.
However, while it works fine for the files that exist, it still says "Found the file" even if the file isn't there and sources the bash from an empty file because of the -f flag. If I remove the -f flag then it works and says "Couldn't find it" but it also returns an HTTP error since the file isn't there and as I said, I want to hide the errors too.
How can I work this around?

The result code from source is simply the last command in the sourced file. If the file is empty (as it will be if curl fails) that's a success.
What you can do is guard against an error from curl separately.
if source <(curl -s -f "http://example.com/$1.txt" || echo "exit $?"); then

Related

redirect screen output to file

I'm trying to redirect the screen output to a log file but I don't seem to be getting this right, see the code below:
DT=$(date +%Y-%m-%d-%H-%m-%s)
echo $DT > log_copy_$DT.txt
cat dirfiles.txt | while read f ; do
dest=/mydir
scp "${f}" $dest >> log_copy_$DT.txt 2>&1
done
All I get is a file with the date, but not the screen results (I need to see if the files copied correctly).
So, basically I'm appending the results of the scp command into the log and doing the 2>&1 so that the standard output screen is written to the file but doesn't seem to work.
I need to run this on a crontab so I'm not sure if the screen contents will even go to the log once I set it up.
Well, after investigating, it seems scp can't really write standard screen output to a file, it kinda cancels the standard out as it shows % progress, so I ended up doing this:
scp "${f}" $dest && echo $f successfully copied! >> log_copy_$DT.txt
basically, it it can copy the file over, then it writes a message saying it was OK.

Checkin if a Variable File is in another directory

I'm looking to check if a variable file is in another directory, and if it is, stop the script from running any farther. So far I have this:
#! /bin/bash
for file in /directory/of/variable/file/*.cp;
do
test -f /directory/to/be/checked/$file;
echo $?
done
I ran an echo of $file and see that it includes the full path, which would explain why my test doesn't see the file, but I am at a loss for how to move forward so that I can check.
Any help would be greatly appreciated!
Thanks
I think you want
#! /bin/bash
for file in /directory/of/variable/file/*.cp ; do
newFile="${file##*/}"
if test -f /directory/to/be/checked/"$newFile" ; then
echo "/directory/to/be/checked/$newFile already exists, updating ..."
else
echo "/directory/to/be/checked/$newFile not found, copying ..."
fi
cp -i "$file" /directory/to/be/checked/"$newFile"
done
Note that you can replace cp -i with mv -i and move the file, leaving no file left behind in /directory/of/variable/file/.
The -i option means interrogate (I think), meaning if the file is already there, it will ask you overwrite /directory/to/be/checked/"$newFile" (or similar) to which you must reply y. This will only happen if the file already exists in the new location.
IHTH
The command basename will give you just the file (or directory) without the rest of the path.
#! /bin/bash
for file in /directory/of/variable/file/*.cp;
do
test -f /directory/to/be/checked/$(basename $file);
echo $?
done

bash If statement failing

Im working on a bash script to check an ftp site to see if some files exist on it. It works by looping through an array of files using curl to check if the file exists on the ftp server. If it doesnt then curl should output an error which im looking for in my if loop and echoing a result based on it. Code below:
#!/bin/bash
# script variables
ftpaddress=ftpaddress
ftplocation=folderlocation
ftpusername=ftpusername
ftppassword=ftppassword
err="curl: (19) Given file does not exist"
# Initialise array of files
files=( "file1.xml" "file2.xml" "zy.xml" )
for f in "${files[#]}"; do
result=(curl ftp://$ftpaddress$ftplocation$f --user $ftpusername:$ftppassword --head)
if [[ "$result" == "$err" ]]; then
echo $f " Does not exist!!!!"
else
echo $f "Exists"
fi
done
Something about the if loop is failing, ive tried lots of variations on it but have been unable to find one that works. At the moment the result is never matching the error. When I run the curl just from the command line it outputs the error i have set to $err if the file doesnt exist but when running the script the else branch is being selected everytime saying the file does exist. I've even tried setting the error to be*"19"*and it still doesnt match. I've spent a lot of time looking it up and testing it but have had no luck so would appreciate any help that can be given.
Thanks
( ) will get you the return value $( ) will get you stdout
result=$(curl ftp://$ftpaddress$ftplocation$f --user $ftpusername:$ftppassword --head 2>&1)

Create a detailed self tracing log in bash

I know you can create a log of the output by typing in script nameOfLog.txt and exit in terminal before and after running the script, but I want to write it in the actual script so it creates a log automatically. There is a problem I'm having with the exec >>log_file 2>&1 line:
The code redirects the output to a log file and a user can no longer interact with it. How can I create a log where it just basically copies what is in the output?
And, is it possible to have it also automatically record the process of files that were copied? For example, if a file at /home/user/Deskop/file.sh was copied to /home/bckup, is it possible to have that printed in the log too or will I have to write that manually?
Is it also possible to record the amount of time it took to run the whole process and count the number of files and directories that were processed or am I going to have to write that manually too?
My future self appreciates all the help!
Here is my whole code:
#!/bin/bash
collect()
{
find "$directory" -name "*.sh" -print0 | xargs -0 cp -t ~/bckup #xargs handles files names with spaces. Also gives error of "cp: will not overwrite just-created" even if file didn't exist previously
}
echo "Starting log"
exec >>log_file 2>&1
timelimit=10
echo "Please enter the directory that you would like to collect.
If no input in 10 secs, default of /home will be selected"
read -t $timelimit directory
if [ ! -z "$directory" ] #if directory doesn't have a length of 0
then
echo -e "\nYou want to copy $directory." #-e is so the \n will work and it won't show up as part of the string
else
directory=/home/
echo "Time's up. Backup will be in $directory"
fi
if [ ! -d ~/bckup ]
then
echo "Directory does not exist, creating now"
mkdir ~/bckup
fi
collect
echo "Finished collecting"
exit 0
To answer the "how to just copy the output" question: use a program called tee and then a bit of exec magic explained here:
redirect COPY of stdout to log file from within bash script itself
Regarding the analytics (time needed, files accessed, etc) -- this is a bit harder. Some programs that can help you are time(1):
time - run programs and summarize system resource usage
and strace(1):
strace - trace system calls and signals
Check the man pages for more info. If you have control over the script it will be probably easier to do the logging yourself instead of parsing strace output.

How do I kill a Bash script if it can't find or read a file?

I have written a small bash program which needs to read a file with name input. I want the script to print the message file not found and exit or kill itself if it can't find the file.
Just before reading, check if the file exists:
if [ ! -f input ]; then
echo "File Not found"
exit 1
fi
Use the Bash Exit Handler
You can use Bash's set -e option to handle most similar situations automatically, with system-generated (but generally sensible) error messages. For example:
$ set -e; ls /tmp/doesnt_exist
ls: cannot access /tmp/doesnt_exist: No such file or directory
Note that the -e option will also cause the current shell to exit immediately with a non-zero exit status after displaying the error message. This is a quick-and-dirty way to get what you want.
Manually Test for a Readable File
If you really need a custom message, then you want to use a test conditional. For example, to ensure that a file exists and is readable you could use something similar to the following:
if [[ -r "/path/to/input" ]]; then
: # do something with "input"
else
# Send message to standard error.
echo "file not found" > /dev/stderr
# Exit with EX_DATAERR from sysexits.h.
exit 65
fi
See Also
See man 1 test for a more complete list of possible test conditionals.

Resources