I want to write a shell script to check a file on Linux and notify me if the file has been modified or changed.
For example: if /etc/sysconfig/network-scripts/ifcfg-eth0 has been changed, the script should notify me.
This is my code and it doesn't work, please help me:
#!/bin/bash
while true
do
#ATIME=`stat -c %Z /:path/to/the/file.txt`
#lmodiff= `stat -c %y /etc/sysconfig/network-scripts/ifcfg-eth0 | sed 's/^\([0-9\-]*\).*/\1/'`
lmd="2014-09-15"
cmd=`stat -c %y /etc/sysconfig/network-scripts/ifcfg-eth0 | sed 's/^\([0-9\-]*\).*/\1/'`
if [[ "$lmd" != "$cmd" ]]
then
echo "RUN COMMNAD"
#LTIME=$ATIME
else
echo "equal"
fi
done
Can you help me to improve my code?
I might do something like this:
#!/bin/bash
SLEEP=5
FILE=/path/to/file
SUM=$( md5sum $FILE )
while : ; do
sleep $SLEEP
NEWSUM=$( md5sum $FILE )
if [ "$SUM" != "$NEWSUM" ]; then
echo "RUN COMMAND"
SUM=$NEWSUM
else
echo "equal"
fi
done
Related
I am trying to search content of file 1 into file 2 and if the content is found then store in found.csv file or store in notfound.csv file
Below is my code,
cd /mnt/data/dobiminer/scripts
usage="Usage:sh scriptname.sh 'ToSearchFile' 'MainSearchFile' 'CR' "
Date=`date +%m%d%y%H%M%S`
File=$(<$2)
echo "File Input $2"
echo $File
if [ $# != 3 ]
then
echo $usage
exit 1
else
echo > "$3-Found-$Date.csv"
echo > "$3-NotFound-$Date.csv"
for MasterClip in `cat $1`
do
echo $MasterClip
String=$(echo "$File" | grep -x $MasterClip)
echo $String
if [ -z $String ];
then
echo "NotFound"
echo $MasterClip >> "$3-NotFound-$Date.csv"
else
echo "Found"
echo $MasterClip >> "$3-Found-$Date.csv"
fi
done
fi
My guess is that the below line of code is not working, as whenever I am running the code, the string value is empty only. It is not catching the search value into it.
String=$(echo "$File" | grep -x $MasterClip)
echo $String
I tried multiple things but not sure where I am going wrong.
THanks for helping me out
I've recently started working with the getopts command in bash. I am confused as to why my script runs the dafult action "cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl" when arguments have been provided. I only want that to run if no arguments were passed to the shell script. I've used getopts:Std in perl where I was able to code somthing like:
unless ($opts{d}) {
do something...}
How would I code something like that in a shell script? Also, how would I code logic such as this:
if ($opts{c}) {
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -c
}
elsif ($opts{d} {
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -d
My code:
#!/bin/sh
while getopts cd name
do
case $name in
c)copt=1;;
d)dopt=1;;
*)echo "Invalid arg";;
esac
done
if [[ ! -z $copt ]] #Specifies what happens if the -c argument was provided
then
echo "CSV file created!"
cat "~/bin/Temp/log.txt" | ~/bin/Scripts/vpnreport/report.pl -c
fi
if [[ ! -z $dopt ]] #Specifies what happens if the -d argument was provided
then
echo "Debug report and files created"
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -d
fi
if [[ ! -z $name ]] #Specifies what happens if no argument was provided
then
echo "Running standard VPN report"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl
fi
shift $(($OPTIND -1))
My Output:
[~/bin/Scripts/report]$ sh getoptstest.sh
Running standard report
[~/bin/Scripts/report]$ sh getoptstest.sh -d
Debug report and files created
Running standard report
[~/bin/Scripts/report]$
The two getopts commands are vasty different from bash to perl and I just can't seem to get the hang of the bash varient even after reading several tutorials. Any help would be greatly appreciated!
On the final run of getopts, your variable (name) will be set to "?".
#!/bin/bash
while getopts abc foo; do :; done
echo "<$foo>"
Output of the above:
$ ./mytest.sh
<?>
$ ./mytest.sh -a
<?>
Insead, use elif, which is like Perl's elsif:
if [[ ! -z $copt ]]
then
# ...
elif [[ ! -z $dopt ]]
then
# ...
else
# ...
fi
Or test if [[ -z $copt && -z $dopt ]], or so forth. Other notes:
See the official if and case documentation in the Bash manual under "Conditional Constructs".
[[ ! -z $name ]] means the same as the more-direct [[ -n $name ]].
Use #!/bin/bash instead of #!/bin/sh, or switch off of [[ in favor of [. The double square bracket (and your use thereof) is specific to bash, and rarely works with sh.
I took Jeff's answer and rewrote my script so it works now:
#!/bin/bash
while getopts cd name
do
case $name in
c)carg=1;;
d)darg=1;;
*)echo "Invalid arg";;
esac
done
#Specifies what happens if the -c argument was provided:
if [[ ! -z $carg ]]
then
if [[ -z $darg ]]
then
echo "CSV created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -c
else
echo "Debug CSV created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -cd
fi
fi
#Specifies what happens if the -d argurment was provided:
if [[ ! -z $darg ]]
then
echo "Debug report created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -d
#Specifies what happens if no argument was provided:
else
echo "Standard report created"
cat ~bin/Temp/logs.txt | ~bin/Scripts/report.pl
fi
Thank you again for your assistance!
Sorry for asking this question again. I have already received answer but with using find but unfortunately I need to write it without using any predefined commands.
I am trying to write a script that will loop recursively through the subdirectories in the current directory. It should check the file count in each directory. If file count is greater than 10 it should write all names of these file in file named "BigList" otherwise it should write in file "ShortList". This should look like:
---<directory name>
<filename>
<filename>
<filename>
<filename>
....
---<directory name>
<filename>
<filename>
<filename>
<filename>
....
My script only works if subdirectories don't include subdirectories in turn.
I am confused about this because it doesn't work as I expect.
Here is my script
#!/bin/bash
parent_dir=""
if [ -d "$1" ]; then
path=$1;
else
path=$(pwd)
fi
parent_dir=$path
loop_folder_recurse() {
local files_list=""
local cnt=0
for i in "$1"/*;do
if [ -d "$i" ];then
echo "dir: $i"
parent_dir=$i
echo before recursion
loop_folder_recurse "$i"
echo after recursion
if [ $cnt -ge 10 ]; then
echo -e "---"$parent_dir >> BigList
echo -e $file_list >> BigList
else
echo -e "---"$parent_dir >> ShortList
echo -e $file_list >> ShortList
fi
elif [ -f "$i" ]; then
echo file $i
if [ $cur_fol != $main_pwd ]; then
file_list+=$i'\n'
cnt=$((cnt + 1))
fi
fi
done
}
echo "Base path: $path"
loop_folder_recurse $path
How can I modify my script to produce the desired output?
This bash script produces the output that you want:
#!/bin/bash
bigfile="$PWD/BigList"
shortfile="$PWD/ShortList"
shopt -s nullglob
loop_folder_recurse() {
(
[[ -n "$1" ]] && cd "$1"
for i in */; do
[[ -d "$i" ]] && loop_folder_recurse "$i"
count=0
files=''
for j in *; do
if [[ -f "$j" ]]; then
files+="$j"$'\n'
((++count))
fi
done
if ((count > 10)); then
outfile="$bigfile"
else
outfile="$shortfile"
fi
echo "$i" >> "$outfile"
echo "$files" >> "$outfile"
done
)
}
loop_folder_recurse
Explanation
shopt -s nullglob is used so that when a directory is empty, the loop will not run. The body of the function is within ( ) so that it runs within a subshell. This is for convenience, as it means that the function returns to the previous directory when the subshell exits.
Hopefully the rest of the script is fairly self-explanatory but if not, please let me know and I will be happy to provide additional explanation.
I need help with replacing the following script with a different format where a configuration file, and a loop is used.
[FedoraC]$ cat script.sh
#!/bin/bash
grep -q /tmp /etc/fstab
if [ $? -eq 0 ]; then
echo "True"
else
echo "False"
fi
mount | grep ' /tmp' | grep nodev
if [ $? -eq 0 ]; then
echo "True"
else
echo "False"
fi
mount | grep /tmp | grep nosuid
if [ $? -eq 0 ]; then
echo "True"
else
echo "False"
fi
So far I have the following script which should take the values from a source/conf file and run each command found in the conf file one by one. After the command is executed the output would be "True" or "False"
conf file is formed by Unix commands: /opt/conf1
[FedoraC]$ cat conf1
grep -q /tmp /etc/fstab
mount | grep /tmp | grep nodev
mount | grep /tmp | grep nosuid
mount | grep /tmp | grep noexec
[FedoraC]$ cat new_script.sh
#!/bin/bash
. conf1
for i in $#;
do $i
if [ $i -eq 0 ]; then
echo "Passed"
else
echo "Failed"
fi
done
Instead of displaying the output based on the conditional statement, the script runs each line one by one from conf1, and not echo messages are seen.
Can I get some help please.
try this:
#! bin/bash
while read L; do
echo $L'; exit $?'|sh
if [ $? -eq 0 ]; then
echo Pass
else
echo Failed
fi
done < conf1
The more robust and canonical way to do this would be to have a directory /opt/conf1.d/, and put each of your lines as an executable script in this directory. You can then do
for file in /opt/conf1.d/*
do
[[ -x $file ]] || continue
if "$file"
then
echo "Passed"
else
echo "Failed"
fi
done
This has the advantages of supporting multi-line scripts, or scripts with more complex logic. It also lets you write the check script in any language, and lets scripts and packages add and remove contents easily and non-interactively.
If you really want to stick with your design, you can do it with:
while IFS= read -r line
do
if ( eval "$line" )
then
echo "Passed"
else
echo "Failed"
fi
done < /opt/conf1
The parentheses in the if statement runs eval in a subshell, so that lines can't interfere with each other by setting variables or exiting your entire loop.
This post is updated, look below for the solution.
i have the need to check a folder for a presence of a file, which is not always present.
i made a script like this:
#!/bin/sh
while true; do
file=/path/to/file
if [[ "$file" = *filename* ]]
then
echo "$file is present"
else
echo "No present"
fi
sleep 3
done
Works perfectly, except for the fact that the "$file is present" is continuosly repeated, until i delete or move the file.
Which command can I insert after "echo "$file is present" to stop the alert but continue to check for this file (eg when the file will be again available) ?
Thank you.
Since i can't add an answer until 8 hours, i post here my solution:
In anyway i have solved using this script: comparing the time of the file with the current date and then, using "touch" changing the date to 10 seconds ago:
#!/bin/sh
while true
do
cd $(dirname "$0")
current=$(pwd)
cd /boot/home/Downloads
last=$(ls -t | head -n1)
name=$(basename "$last")
filedate=$(date -r "$last" +%G%m%d%H%M%S)
currentdate=$(date +%G%m%d%H%M%S)
if [ "$filedate" -eq "$currentdate" ]
then
echo "$name" "is present"
touch -d '-10 seconds' "$name"
fi
done
Now works as espected and indipendently from the file name!
Alert me about every new file just once and keep to watch that folder :-)
To keep the whole history of script, below there is the script of iamauser. I have a little bit improved this script: now it alert me for every new file (indipendentely from name, kind and so on) inside a folder and also alert me for deleted files :-)
#!/bin/bash
cd /boot/home
filename=$(ls -t | head -n1)
tstamp=$(stat --print "%Y" "$filename")
while true; do
prev=$(ls "/boot/home/Downloads" | tr '\n' '\n' > /tmp/prev.txt)
check=$(ls -t /boot/home/Downloads | head -n1)
if [ ! -d "$filename" ]; then
after=$(ls "/boot/home/Downloads" | tr '\n' '\n' > /tmp/after.txt)
echo "Not present";
sleep 5;
elif [[ "$filename" == "$filename" && $tstamp -ne $(stat --print "%Y" "$filename") ]]; then
sleep 2
difference=$(comm -2 -3 "/tmp/after.txt" "/tmp/prev.txt">/tmp/Diff.txt)
lost=$(cat /boot/common/cache/tmp/Diff.txt)
alert --idea "/boot/home/Downloads: $check is the most recent file in this folder.";
alert --idea "/boot/home/Downloads: $lost removed.";
tstamp=$(stat --print "%Y" "$filename")
else
sleep 3;
fi
done
Something like this may work. I am checking the timstamp of the file to check if there is a new copy of the same filename in the folder.
#!/bin/bash
filename="/path/to/file"
tstamp=$(stat --print "%Y" "$file")
while true; do
if [ ! -f "$filename" ]; then
echo "Not present";
sleep 5;
elif [[ "$filename" == "myfile" && $tstamp -ne $(stat --print "%Y" "$filename") ]]; then
echo "$filename is present";
tstamp=$(stat --print "%Y" "$filename")
else
sleep 3;
fi
done
I tested the script, by touching the filename while the script was running, each time I touched, it printed $filename is present.
Sure, konsolebox; you're right. my script isn't perfect also if i add a sleep to reduce CPU usage.
In anyway, maybe, i miss something with the script from iamauser:
The above script print the echo out when the file is not present, but doesn't print echo out when is present.. Why?
In anyway, since i'd like to experiment, i was also thinking to another way: check the number of files inside a folder using "ls -1 | wc -l", a new file is added and the number of files is +1 than "ls -1 | wc -l"
and, so, i can be alerted indipendently from the file name.. If there is any kind of file with any name, the script should alert me once, while keep to check for new files in the folder.
Any other suggestion?
Thank you!
UPDATE
Ok: this is the definitive revision of the script:
When a new file is written in a folder, this script alert me about. And if I remove this file, the script will alert me, of the most recent file present in that folder.
Very nice, since this is what i was looking for :-)
Since I am on Haiku, i have also replaced the "echo" with alert, an alert window, a sort of graphic "echo".
#!/bin/bash
cd /boot/home
filename=$(ls -t | head -n1)
tstamp=$(stat --print "%Y" "$filename")
while true; do
check=$(ls -t /boot/home/Downloads | head -n1)
if [ ! -d "$filename" ]; then
echo "Not present";
sleep 5;
elif [[ "$filename" == "$filename" && $tstamp -ne $(stat --print "%Y" "$filename") ]]; then
alert --idea "/boot/home/Downloads: $check is the most recent file in this folder";
tstamp=$(stat --print "%Y" "$filename")
else
sleep 3;
fi
done