getops if than else - bash

I have working getops function
m) MONTH=$OPTARG
for file in *eqllogmgr* ;
do ftx $file |
layoutcc ;
cat $file | grep '\-'$MONTH |
perl -ne 'print if /-2018/' |
perl -pe 's/......-2018/\e[1;32m$&\e[0m/g' |
sed '$d' ;
echo ;
ft1 ;
done ;;
I am trying to alter the grep to evaluate the $MONTH and use the grep i need depending on what the user inputs for the MONTH.
I tried this
t) MONTH=$OPTARG
if [[ $MONTH =~ ^[0-9]+$ ]]; then
for file in *eqllogmgr* ;
do ftx $file |
layoutcc ;
cat $file | grep $MONTH |
perl -ne 'print if /-2018/' |
perl -pe 's/......-2018/\e[1;32m$&\e[0m/g' |
sed '$d' ;
echo ;
ft1 ;
fi ;
done ;;
else
for file in *eqllogmgr* ;
do ftx $file |
layoutcc ;
cat $file | grep '\-'$MONTH |
perl -ne 'print if /-2018/' |
perl -pe 's/......-2018/\e[1;32m$&\e[0m/g' |
sed '$d' ;
echo ;
ft1 ;
fi ;
done ;;
But i get errors for the fi
i have tried moving that fi around and i cant seem to figure out what i am missing.
Basicly i want to look for a number in the variable and if it has one
run the grep on the base variable $MONTH
If it has no number i want to grep the variable with a dash in front of it
'-'$MONTH
I tired this as well and i get the same
syntax error near unexpected token `else'
so i am pretty sure its just the way i am using the if else statement
u) MONTH=$OPTARG
for file in *eqllogmgr* ;
do ftx $file |
layoutcc ;
cat $file |
if [[ $MONTH =~ ^[0-9]+$ ]]; then
grep $MONTH |
else
grep '\-'$MONTH |
fi
perl -ne 'print if /-2018/' |
perl -pe 's/......-2018/\e[1;32m$&\e[0m/g' |
sed '$d' ;
echo ;
ft1 ;
done ;;
Adding my final working version for reference ===========================
m) MONTH=$OPTARG
if [[ "$MONTH" = [0-9]* ]]; then
grep_expr=$MONTH
else
grep_expr='\-'$MONTH
fi
for file in *eqllogmgr* ; do
ftx "$file" | layoutcc
grep "$grep_expr" "$file" | perl -ne 'print if /-2018/' | perl -pe 's/......-2018/\e[1;32m$&\e[0m/g' | sed '$d'
echo
ft1
done
;;

What (I think) you're trying to do:
case-value)
if ... ; then
for ...; do
done
else
for ...; do
done
fi
;;
What you have shown in your question:
case-value)
if ...; then
for ...; do
fi
done
;;
else
for ...; do
fi
done
;;
The first fi and the first ;; are both extraneous. The second fi is misplaced inside the second for loop.
In the edit you made to your question, you seem to have changed tack and are now trying to accomplish your goal with a single for loop containing an if/else, as opposed to an if/else with a for loop in each clause. That's definitely more efficient, but you can't use an if/else the way you're trying to. At least, not without a lot of unnecessary messiness (actually you can, but you have to get rid of a couple extra |s -- see below). Since your grep expression only varies by a couple characters, you can just store the expression in a variable, and use your if/else to set the expression:
u) MONTH=$OPTARG
if [[ "$MONTH" =~ ^[0-9]+$ ]]; then
grep_expr='\-'$MONTH
else
grep_expr=$MONTH
fi
for file in *eqllogmgr* ; do
ftx "$file" | layoutcc
grep "$grep_expr" "$file" |
perl -ne 'print if /-2018/' |
perl -pe 's/......-2018/\e[1;32m$&\e[0m/g' |
sed '$d'
echo
ft1
done
;;
Note: I also added some quoting, removed the unnecessary colons, and got rid of the unnecessary cat command (just pass the filename directly to grep - no need for an extra pipe).
* Turns out what you were trying would actually work, although I personally don't think it's very concise. Example:
$ show=men
$ echo -e "Alice\nBob\nCarol\nDavid" | if [[ "$show" = "men" ]]; then egrep 'Bob|David'; else egrep 'Alice|Carol'; fi
Bob
David
$ show=women
$ echo -e "Alice\nBob\nCarol\nDavid" | if [[ "$show" = "men" ]]; then egrep 'Bob|David'; else egrep 'Alice|Carol'; fi
Alice
Carol

Related

How to bruteforce my own encrypted .dmg with known base password

I was fooling around with Disk Utility's encrypted .dmg feature. I accidentally put an important file in there and partly forgot the password. (I KNOW!) I know exactly what the first part of the password was, but the last 2-4 digits I have just a cloudy idea of. Something like Myword55& or Urword934!
How could I bruteforce to try all the password combinations automatically? I found this following bash script but don't know how to modify it to my exact needs:
#!/bin/bash
dmgfile="Your Encrypted File.dmg"
function TryPassword
{
echo -n "$1 "
r=$(echo -n "$1" | hdiutil verify -stdinpass "$dmgfile" 2>&1)
if ! [[ $r =~ "Authentication error" ]]; then
echo ""
echo "Found! The password is: $1"
exit
fi
}
chars=$(echo {0..9} {A..z})
alphanum=( $(echo $chars | sed -E 's/[^A-Za-z0-9 ]+/ /g') )
letter=( $(echo $chars | sed -E 's/[^A-Za-z ]+/ /g') )
lowercase=( $(echo $chars | sed -E 's/[^a-z ]+/ /g') )
uppercase=( $(echo $chars | sed -E 's/[^A-Z ]+/ /g') )
digit=( $(echo $chars | sed -E 's/[^0-9 ]+/ /g') )
for a in "${letter[#]}"; do
for b in "${lowercase[#]}"; do
for c in "${digit[#]}"; do
TryPassword "$a$b$c"
done
done
done
EDIT: got it!
And I found the password I was looking for...
Turns out the script I had had a typo at the "digits" word and therefore didn't execute properly. I modified the for loop to:
for a in "${digit[#]}"; do
for b in "${digit[#]}"; do
TryPassword "Myword$a$b%"
done
done
(the "%" is just one of the special characters I tried)

Shell script: check if any files in one directory are newer than any files in another directory

I want to run a command in a shell script if files in one directory have changed more recently than files in another directory.
I would like something like this
if [ dir1/* <have been modified more recently than> dir2/* ]; then
echo 'We need to do some stuff!'
fi
As described in BashFAQ #3, broken down here into reusable functions:
newestFile() {
local latest file
for file; do
[[ $file && $file -nt $latest ]] || latest=$file
done
}
directoryHasNewerFilesThan() {
[[ "$(newestFile "$1"/*)" -nt "$(newestFile "$2" "$2"/*)" ]]
}
if directoryHasNewerFilesThan dir1 dir2; then
echo "We need to do something!"
else
echo "All is well"
fi
If you want to count the directories themselves as files, you can do that too; just replace "$(newestFile "$1"/*)" with "$(newestFile "$1" "$1"/*)", and likewise for the call to newestFile for $2.
Using /bin/ls
#!/usr/bin/ksh
dir1=$1
dir2=$2
#get modified time of directories
integer dir1latest=$(ls -ltd --time-style=+"%s" ${dir1} | head -n 2 | tail -n 1 | awk '{print $6}')
integer dir2latest=$(ls -ltd --time-style=+"%s" ${dir2} | head -n 2 | tail -n 1 | awk '{print $6}')
#get modified time of the latest file in the directories
integer dir1latestfile=$(ls -lt --time-style=+"%s" ${dir1} | head -n 2 | tail -n 1 | awk '{print $6}')
integer dir2latestfile=$(ls -lt --time-style=+"%s" ${dir2} | head -n 2 | tail -n 1 | awk '{print $6}')
#sort the times numerically and get the highest time
val=$(/bin/echo -e "${dir1latest}\n${dir2latest}\n${dir1latestfile}\n${dir2latestfile}" | sort -n | tail -n 1)
#check to which file the highest time belongs to
case $val in
#(${dir1latest}|${dir1latestfile})) echo $dir1 is latest ;;
#(${dir2latest}|${dir2latestfile})) echo $dir2 is latest ;;
esac
It's simple, get times stamps of both the folders in machine format(epoch time) then do simple comparison. that's all

Grep command in array

For a homework assignment I have to Take the results from the grep command, and write out up to the first 5 of them, numbering them from 1 to 5. (Print the number, then a space, then the line from grep.) If there are no lines, print a message saying so. So far I managed to store the grep command in an array but this is where I've gotten stuck: Can anyone provide guidance as to how to proceed in printing this as stated above
pattern="*.c"
fileList=$(grep -l "main" $pattern)
IFS=$"\n"
declare -a array
array=$fileList
for x in "${array[#]}"; do
echo "$x"
done
you can grep options -c and -l
pattern="*.c"
searchPattern="main"
counter=1
while read -r line ; do
IFS=':' read -r -a lineInfo <<< "$line"
if [[ $counter > 5 ]]; then
exit 1
fi
if [[ ${lineInfo[1]} > 0 ]]; then
numsOfLine=""
while read -r fileline ; do
IFS=':' read -r -a fileLineInfo <<< "$fileline"
numsOfLine="$numsOfLine ${fileLineInfo[0]} "
done < <(grep -n $searchPattern ${lineInfo[0]})
echo "$counter ${lineInfo[0]} match on lines: $numsOfLine"
let "counter += 1"
else
echo "${lineInfo[0]} no match lines"
fi
done < <(grep -c $searchPattern $pattern)
If you're only allowed to use grep and bash(?):
pattern="*.c"
fileList=($(grep -l "main" $pattern))
if test ${#fileList[#]} = 0 ; then
echo "No results"
else
n=0
while test $n -lt ${#fileList[#]} -a $n -lt 5 ; do
i=$n
n=$(( n + 1 ))
echo "$n ${fileList[$i]}"
done
fi
If you are allowed to use commands in addition to grep, you can pipe the results through nl to add line numbers, then head to limit the results to the first 5 lines, then a second grep to test if there were any lines. For example:
if ! grep -l "main" $pattern | \
nl -s ' ' | sed -e 's/^ *//' | \
head -n 5 | grep '' ; then
echo "No results"
fi

Remove one directory component from path (string manipulation)

I'm looking for the easiest and most readable way to remove a field from a path. So for example, I have /this/is/my/complicated/path/here, and I would like to remove the 5th field ("/complicated") from the string, using bash commands, so that it becomes /this/is/my/path.
I could do this with
echo "/this/is/my/complicated/path/here" | cut -d/ -f-4
echo "/"
echo "/this/is/my/complicated/path/here" | cut -d/ -f6-
but I would like this done in just one easy command, something that would like
echo "/this/is/my/complicated/path" | tee >(cut -d/ -f-4) >(cut -d/ -f6-)
except that this doesn't work.
With cut, you can specify a comma separated list of fields to print:
$ echo "/this/is/my/complicated/path/here" | cut -d/ -f-4,6-
/this/is/my/path/here
So, it's not really necessary to use two commands.
How about using sed?
$ echo "/this/is/my/complicated/path/here" | sed -e "s%complicated/%%"
/this/is/my/path/here
This removes the 5th path element
echo "/this/is/my/complicated/path/here" |
perl -F/ -lane 'splice #F,4,1; print join("/", #F)'
just bash
IFS=/ read -a dirs <<< "/this/is/my/complicated/path/here"
newpath=$(IFS=/; echo "${dirs[*]:0:4} ${dirs[*]:5}")
Anything wrong with a bash script?
#!/bin/bash
if [ -z "$1" ]; then
us=$(echo $0 | sed "s/^\.\///") # Get rid of a starting ./
echo " "Usage: $us StringToParse [delimiterChar] [start] [end]
echo StringToParse: string to remove something from. Required
echo delimiterChar: Character to mark the columns "(default '/')"
echo " "start: starting column to cut "(default 5)"
echo " "end: last column to cut "(default 5)"
exit
fi
# Parse the parameters
theString=$1
if [ -z "$2" ]; then
delim=/
start=4
end=6
else
delim=$2
if [ -z "$3" ]; then
start=4
end=6
else
start=`expr $3 - 1`
if [ -z "$4" ]; then
end=6
else
end=`expr $4 + 1`
fi
fi
fi
result=`echo $theString | cut -d$delim -f-$start`
result=$result$delim
final=`echo $theString | cut -d$delim -f$end-`
result=$result$final
echo $result

Simplest Bash code to find what files from a defined list don't exist in a directory?

This is what I came up with. It works perfectly -- I'm just curious if there's a smaller/crunchier way to do it. (wondering if possible without a loop)
files='file1|file2|file3|file4|file5'
path='/my/path'
found=$(find "$path" -regextype posix-extended -type f -regex ".*\/($files)")
for file in $(echo "$files" | tr '|', ' ')
do
if [[ ! "$found" =~ "$file" ]]
then
echo "$file"
fi
done
You can do this without invoking any external tools:
IFS="|"
for file in $files
do
[ -f "$file" ] || printf "%s\n" "$file"
done
Your code will break if you have file names with whitespace. This is how I would do it, which is a bit more concise.
echo "$files" | tr '|' '\n' | while read file; do
[ -e "$file" ] || echo "$file"
done
You can probably play around with xargs if you want to get rid of the loop all together.
$ eval "ls $path/{${files//|/,}} 2>&1 1>/dev/null | awk '{print \$4}' | tr -d :"
Or use awk
$ echo -n $files | awk -v path=$path -v RS='|' '{printf("! [[ -e %s ]] && echo %s\n", path"/"$0, path"/"$0) | "bash"}'
without whitespace in filenames:
files=(mbox todo watt zoff xorf)
for f in ${files[#]}; do test -f $f || echo $f ; done

Resources