breaking the parameters of shell script into several causes errors - linux

I have a shell script using a phantom js function
The Phantom JS function crashes when it is run on too many urls apparently, I tried to rewrite it to only do part at a time but I get an error where the $url variable does not change so it always copies down the same url though it appears to write down the actual size of the site.
If I could be helped through that error that would be glorious.
#!/bin/bash
echo "Importing URLs..."
file=sizeurls.csv
url=""
while IFS= read -r line
do
url+=" "
url+=$line
done < "$file"
echo "Gathering page sizes..."
phantomjs yslow.js --info basic --format plain $url | grep 'url\|size' > temp.txt
echo "Formatting data..."
sed -i 's/size://g' temp.txt
sed -i 's/url://g' temp.txt
paste - - -d, < temp.txt > pagesize.csv
echo "Done!"
version that is supposed to do part at a time, it may be mortally screwed because I just messed with it a little bit an d I am not sure I returned it to the previous state
#!/bin/bash
echo "Importing URLs..."
file=sizeurls.csv
url=""
i=0;
while IFS= read -r line
do
while [ $i -le 10 ] #10 at a time i < 10
do
url+=" "
url+=$line
i=$((i+1));
done < "$file"
phantomjs yslow.js --info basic --format plain $url | grep 'url\|size' >> temp.txt
#echo "Formatting data..."
sed -i 's/size://g' temp.txt
sed -i 's/url://g' temp.txt
paste - - -d, < temp.txt >> pagesize.csv
done < "$file"
i = 0
echo "Done!"

Why not simply do one at a time?
#!/bin/bash
echo "Importing URLs..."
file=sizeurls.csv
echo "Gathering page sizes..."
while IFS= read -r url
do
phantomjs yslow.js --info basic --format plain $url | grep 'url\|size'
done < "$file" > temp.txt
echo "Formatting data..."
sed -i -e 's/size://g' -e 's/url://g' temp.txt
paste - - -d, < temp.txt > pagesize.csv
echo "Done!"

This may give you some ideas (untested, but looks about right). The processing is moved to a function where it is called every 10th URL, and again at the end if there are any leftover URLs.
#!/bin/bash
echo "Importing URLs..."
file=sizeurls.csv
rm pagesize.csv
ProcessURLs () {
echo "Gathering page sizes..."
phantomjs yslow.js --info basic --format plain $# | grep 'url\|size' > temp.txt
echo "Formatting data..."
sed -i 's/size://g' temp.txt
sed -i 's/url://g' temp.txt
paste - - -d, < temp.txt >> pagesize.csv
}
url=""
count=0
while IFS= read -r line
do
url+="$line$ "
(( count++ ))
# Procss URLs in 10-URL chunks
if [[ $count -ge 10 ]] ; then
ProcessURLs $url
url=''
count=0
fi
done < "$file"
# Handle any remaining URLs
[ -n "$url" ] && ProcessURLs $url
echo "Done!"

Related

sed is not working for commenting a line in a file using bash script

I have created a bash script that is used to modify the ulimit of open files in the RHEL server.
so i have reading the lines in the file /etc/security/limits.conf and if the soft/hard limit of the open files are less than 10000 for '*' domain i am commenting the line and adding a new line with soft/hard limit as 10000.
The Script is working as designed but the sed command to comment a line in the script is not working.
Please find the full script below :-
#!/bin/sh
#This script would be called by '' to set ulimit values for open files in unix servers.
#
configfile=/etc/security/limits.conf
help(){
echo "usage: $0 <LimitValue>"
echo -e "where\t--LimitValue= No of files you want all the users to open"
exit 1
}
modifyulimit()
{
grep '*\s*hard\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
grep '*\s*soft\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
}
deleteEofTag(){
sed -i "/\b\(End of file\)\b/d" $configfile
}
addEofTag()
{
echo "#################End of file###################" >> $configfile
}
#-------------Execution of the script starts here ----------------------
if [ $# -ne 1 ];
then
help
else
modifyulimit $1
deleteEofTag
addEofTag
fi
The command sed -i -e 's/$line/#$line/g' $configfile when executed from the terminal is working absolutely fine and it is commenting the line but it is not working when i am executing it from the unix shell script.
interpolation does not work in single quote
use double quote and try
sed -i -e 's/$line/#$line/g'
sed -i -e "s/$line/#$line/g"
also you might try:
sed -i -e s/${line}/#${line}/g
as this will tell the script to take the value of the variable instead of variable as such.

updating a file using tee randomly fails in linux bash script

when using sed -e to update some parameters of a config file and pipe it to | tee (to write the updated content into the file), this randomly breaks and causes the file to be invalid (size 0).
In Summary, this code is used for updating parameters:
# based on the provided linenumber, add some comments, add the new value, delete old line
sed -e "$lineNr a # comments" -e "$lineNr a $newValue" -e "$lineNr d" $myFile | sudo tee $myFile
I set up an script which calls this update command 100 times.
In a Ubuntu VM (Parallels Desktop) on a shared Directory with OSX this
behaviour occurs up to 50 times
In a Ubuntu VM (Parallels Desktop) on the
Ubuntu partition this behaviour occurs up to 40 times
On a native System (IntelNUC with Ubuntu) this behaviour occurs up to 15 times
Can someone explain why this is happening?
Here is a fully functional script where you can run the experiment as well. (All necessary files are generated by the script, so you can simply copy/paste it into a bashscriptfile and run it)
#!/bin/bash
# main function at bottom
#====================
#===HELPER METHOD====
#====================
# This method updates parameters with a new value. The replacement is performed linewise.
doUpdateParameterInFile()
{
local valueOfInterest="$1"
local newValue="$2"
local filePath="$3"
# stores all matching linenumbers
local listOfLines=""
# stores the linenumber which is going to be replaced
local lineToReplace=""
# find value of interest in all non-commented lines and store related lineNumber
lineToReplace=$( grep -nr "^[^#]*$valueOfInterest" $filePath | sed -n 's/^\([0-9]*\)[:].*/\1/p' )
# Update parameters
# replace the matching line with the desired value
oldValue=$( sed -n "$lineToReplace p" $filePath )
sed -e "$lineToReplace a # $(date '+%Y-%m-%d %H:%M:%S'): replaced: $oldValue with: $newValue" -e "$lineToReplace a $newValue" -e "$lineToReplace d" $filePath | sudo tee $filePath >/dev/null
# Sanity check to make sure file did not get corrupted by updating parameters
if [[ ! -s $filePath ]] ; then
echo "[ERROR]: While updating file it turned invalid."
return 31
fi
}
#===============================
#=== Actual Update Function ====
#===============================
main_script()
{
echo -n "Update Parameter1 ..."
doUpdateParameterInFile "Parameter1" "Parameter1 YES" "config.txt"
if [[ "$?" == "0" ]] ; then echo "[ OK ]" ; else echo "[FAIL]"; return 33 ; fi
echo -n "Update Parameter2 ..."
doUpdateParameterInFile "Parameter2" "Parameter2=90" "config.txt"
if [[ "$?" == "0" ]] ; then echo "[ OK ]" ; else echo "[FAIL]"; return 34 ; fi
echo -n "Update Parameter3 ..."
doUpdateParameterInFile "Parameter3" "Parameter3 YES" "config.txt"
if [[ "$?" == "0" ]] ; then echo "[ OK ]" ; else echo "[FAIL]"; return 35 ; fi
}
#=================
#=== Main Loop ===
#=================
#generate file config.txt
printf "# Configfile with 3 Parameters\n#[Parameter1]\n#only takes YES or NO\nParameter1 NO \n\n#[Parameter2]\n#Parameter2 takes numbers\nParameter2 = 100 \n\n#[Parameter3]\n#Parameter3 takes YES or NO \nParameter3 YES\n" > config.txt
cp config.txt config.txt.bkup
# Start the experiment and let it run 100 times
cnt=0
failSum=0
while [[ $cnt != "100" ]] ; do
echo "==========run: $cnt; fails: $failSum======="
main_script
if [[ $? != "0" ]] ; then cp config.txt.bkup config.txt ; failSum=$(($failSum+1)) ; fi
cnt=$((cnt+1))
sleep 0.5
done
regards
DonPromillo
The problem is that you're using tee to overwrite $filepath at the same time as sed is trying to read from it. If tee truncates it first then sed gets an empty file and you end up with a 0 length file at the other end.
If you have GNU sed you can use the -i flag to have sed modify the file in place (other versions support -i but require an argument to it). If your sed doesn't support it you can have it write to a temp file and move it back to the original name like
tmpname=$(mktemp)
sed -e "$lineToReplace a # $(date '+%Y-%m-%d %H:%M:%S'): replaced: $oldValue with: $newValue" -e "$lineToReplace a $newValue" -e "$lineToReplace d" "$filePath" > "$tmpname"
sudo mv "$tmpname" "$filePath"
or if you want to preserve the original permissions you could do
sudo sh -c "cat '$tmpname' > '$filePath'"
rm "$tmpname"
or use your tee approach like
sudo tee "$filePath" >/dev/null <"$tmpname"
rm "$tmpname"

breaking the loop in bash programming

This code is working fine with me I am new to bash programming I want loop to run only once and I dont want loop to run and watermark the all videos. Instead I want to break the loop when first video is done.
#!/bin/bash
#!!!!!!VARIABLES!!!!!!
VIDEOS_PATH='/home/danny/public_html/videowork/'
LOGO_PATH='/home/danny/public_html/watermark_pics/'
DATABASE_INFORMATION='/home/danny/public_html/videowork/db.txt'
#!!!!!!!!!!!!!!!!!!!!!
if find $VIDEOS_PATH -name '*.mp4' 2> /dev/null
then
for file in $(find $VIDEOS_PATH -name '*.mp4')
do
echo "User: ".$(whoami)
echo "File: "$file" has been detected"
sitename=$(echo $file | awk -F $VIDEOS_PATH '{print $2}')
sitename=$(echo $sitename |awk -F '/' '{print $1}')
echo "File sitename is: "$sitename
logo=$LOGO_PATH$sitename.png
echo "Watermark picture has been located in: "$logo
echo "Encoding "$file" to /home/"$sitename"/public_html/yt/"$(basename $file)
ffmpeg -i $file -vcodec libx264 -acodec copy -vf "movie=$logo [watermark]; [in][watermark] overlay=10:10 [out]" /home/$sitename/public_html/yt/$(basename $file)
thumbnail=$(basename $file .mp4)
thumbnail=$VIDEOS_PATH$sitename"/"$(echo $thumbnail).jpg
mv $thumbnail /home/$sitename/public_html/yt/
rm $file
echo "/home/$sitename/public_html/yt/$(basename $file)"
for line in $(cat $DATABASE_INFORMATION)
do
database=$(echo $line | awk -F '|' '{print $1}')
password=$(echo $line | awk -F '|' '{print $2}')
echo "Database detected: "$database
echo "Password: "$password
videoid=$(basename $file .mp4)
if [[ $(echo $database) == $(echo $sitename) ]]
then
php -f /home/danny/public_html/videowork/database_job.php -- $(echo $database) $(echo $password) $(echo $videoid)
#echo "php -f database_job.php -- "$(echo $database)" "$(echo $password)" "$(echo $videoid)
fi
done
done
fi
If I add "break" before last fi? would it be fine? I tried but it didnt work well
Using a looping construct only to break after the first iteration is silly. Instead, don't use that construct at all. For instance, with bash 4.x or newer, you can completely avoid use of find entirely:
#!/bin/bash
shopt -s globstar nullglob
videos=( "$VIDEOS_PATH"/**/*.mp4 )
(( ${#videos[#]} )) || { echo "No videos found" >&2; exit 1; }
file=${videos[0]}
# ...transcode "$file" here
For compatibility with bash 3.x, one might change this a bit to still use find (albeit with -print0 and an appropriate read construct to handle filenames with unusual characters):
#!/bin/bash
IFS= read -r -d '' file < <(find "$VIDEOS_PATH" -name '*.mp4' -print0)
[[ $file ]] || { echo "No videos found" >&2; exit 1; }
# ...transcode "$file" here

Incorrect results from Md5 sum in bash shell script

I'm missing some images that should have been archived when this script runs. I think this may be to do with my indentations or my Md5 sum. I have tried everything I can think of.
here is the code with out the correct indentations:
#!/bin/sh
if [ ! -d "$1" ]; then
echo Directory "$1" cannot be found. Please try again.
exit
fi
if [ $# -eq 1 ]; then
echo "usage: Phar image_path archive_path"
exit
fi
if [ -d "$2" ]; then
echo "archive exists"
else
echo "the directory 'archive' does't exist. Creating directory 'archive'."
mkdir -p ~/archive
fi
find $1 -iname "IMG_[0-9][0-9][0-9][0-9].JPG" | cat > list.txt
[ -f ~/my-documents/md5.txt ] && rm md5.txt || break
while read line;
do md5sum $line | xargs >> md5.txt
done < list.txt
sort -k 1,1 -u md5.txt | cat > uniquemd5.txt
cut -d " " -f 2- uniquemd5.txt > uniquelist.txt
sort uniquelist.txt -r -o uniquelist.txt
for line in $(cat uniquelist.txt)
do
file=$(basename $line) path="$2/file"
if [ ! -f $path ];
then
cp $line $2
else
cp $line $path.JPG
fi
rm uniquelist.txt md5.txt uniquemd5.txt list.txt
done
This loop
while read line;
do md5sum $line | xargs >> md5.txt
done < list.txt
should probably be
while read line;
do md5sum "$line"
done < list.txt > md5.txt
Quote parameter expansions, and it's unclear why you needed.

How to use the case statement to call functions?

Hi I have used this code to find the .java file from the given path and generate the list of the .java files from the path to output file,and count total number of tabs and spaces in each java file.now i need to write the two while loops in function and call that function in case statement, how to do this?
Code:
#!/bin/sh
#
output=/home/user/Desktop/file-list.txt
path=/home/user/Desktop
find $path -type f -name \*.java > $output
echo "Generating files list..."
echo "Done"
while IFS= read file
do
if [ -f "$file" ]; then
spaces=$(tr -cd '\s' < "$file" | wc -c);
echo "$spaces spaces in file $file" >> "/home/user/Desktop/space-count.txt"
fi
done < "$output"
echo "Space Count Done!"
while IFS= read file
do
if [ -f "$file" ]; then
tabs=$(tr -cd '\t' < "$file" | wc -c);
echo "$tabs tabs in file $file" >> "/home/user/Desktop/tab-count.txt"
fi
done < "$output"
echo "Tab Count Done!"
Here is an example of case, but the name of the character could be passed to the function
thereby eliminating the need to case the char.
function count_char
{
flist=$1
ch=$2
case $ch in
" ") chName=space;;
"\t") chName=tab;;
esac
while IFS= read file
do
if [ -f "$file" ]; then
tot=$(tr -cd $ch < "$file" | wc -c);
echo "$tot $chName in file $file" >> "/home/user/Desktop/tab-count.txt"
fi
done < "$flist"
}
# setup code, find command here
# ....
count_char $output " "
count_char $output "\t"

Resources