i just created an argument using IF loop, with the loop i have multiple variables in it. it just happen that only with filename starts with CN are deleted but under the filename under CA are not deleted.
here's my code, appreciate your help. THANKS ! :)
if [ "$retval" = true ]
then
for file_name in "$processdir"/*?.?*; do
filebasename=$(basename "$file_name")
if [ "$prefix" == "CA" ] || [ "$prefix" == "CN" ];
then
rm -f "$file_name"
retval_1="true"
fi
done
fi
You never affect $prefix. I think you don't need this variable
Try this :
if [ "$retval" = true ]
then
for file_name in "$processdir"/*
do
filebasename=$(basename "$file_name")
if [[ "$filebasename" == "CA*" ]] || [[ "$filebasename" == "CN*" ]]
then
rm -f "$file_name"
retval_1="true"
fi
done
fi
thanks for the feedback, but i just used the $prefix for looking up on the filenames that starts with "CA" or "CN" and also for the naming convention of my directory.
here is my edited code:
if [ "$retval" = true ]
then
for file_name in "$processdir$prefix"/*
do
filebasename=$(basename "$file_name")
prefix=${filebasename:0:2}
if [ "$prefix" == "CA" ]|| [ "$prefix" == "CN" ];
then
rm -iv "$file_name"
retval_1="true"
fi
done
fi
Related
I wrote a code for recyclebin file for UNIX. And when i bash recyclebin -i filename,
it reads the getopts passed before the filename and after that it calls test function
and enter into the test function but doesnt enter the for loop inside the function. The program is not going anywhere from there, i am stuck there. Any help what am i doing wrong there
#!bin/bash
### 2. creating directory ~/recyclebin in home if not present
if [[ ! -d $HOME/recyclebin ]]
then
mkdir $HOME/recyclebin
#touch $HOME/.restore.info
fi
if [ -d $HOME/recyclebin ] && [ ! -e $HOME/.restore.info ]
then
touch $HOME/.restore.info
fi
### 4. Test Conditions
function test() {
for arg in $*
do
file=$arg
###No Filename Provided Error
if [ $# -eq 0 ]
then
echo "missing operand"
file="Error"
exit 1
###File Does Not Exist Error
elif [ ! -e $file ]
then
echo "Cannot delete $file: No such file exists"
file="Error"
exit 2
###Directory Name provided
elif [ -d $file ]
then
echo "Cannot delete $file : Not a file."
file="Error"
exit 3
###cannot delete any argument with recycle in it
elif [[ "${file}" =~ .*"recycle".* ]]
then
echo "Attempting to delete recycle – operation aborted"
file="Error"
exit 4
fi
processRequest
done
}
processRequest(){
echo "Entered processRequest"
if [ $noChoice = true ]
then
recycle
elif [ $iOption = true ] && [ $vOption = true ]
then
read -p "recycle: remove file '$file' ? [y/n] " response
case $response in
[yY]*)
recycle
echo "recycle: '$file' is removed";;
*)
continue ;;
esac
elif [ $iOption = true ]
then
read -p "recycle: remove file '$file' ? [y/n] " response
case $response in
[yY]*)
recycle
echo "recycle: '$file' is removed";;
*)
continue ;;
esac
elif [ $vOption = true ]
then
recycle
echo "removed '$file' to the Recycle Bin"
fi
}
### Assigning the values of flename, absolute path and inode to variable
### name, absolute_path and inode before sending it to recyclebin folder
recycle() {
# If no errors mv the file to the recyclebin folder and add to .restore.info file.
if [ $file != "Error" ] ; then
name=$(basename ${file}) #bcz file can be entered with full path
path_cropped=$(readlink -e ${i} | cut -d"/" -f6-)
path=$(dirname $(readlink -e ${i} | cut -d"/" -f6-))
absolute_path="${HOME}/${path_cropped}"
inode=$(stat -c '%i' ${file})
filename=$name"_"$inode
echo $newfilename:$fixedPath >> $HOME/.restore.info
mv $file $recyclepath/$newfilename
fi
}
###--------------------Starts from here after checking dir if exists or not--------------------------------------
###Declaring variables which further fulfills condition to act as i, v, r commands
###as i = iOption; v = vOption; no command = noChoice and recycle files recursively
### = r or R
noChoice=true
iOption=false
vOption=false
removeFolder=false
while getopts ivrRvi opt
do
case $opt in
iv)
iOption=true
vOption=true
noChoice=false
break;;
vi)
iOption=true
vOption=true
noChoice=false
break;;
i)
iOption=true
noChoice=false
break;;
v)
vOption=true
noChoice=false
break;;
r)
removeFolder=true
break;;
R)
removeFolder=true
break;;
esac
done
shift $(($OPTIND - 1))
### CAlling the test function to test all the mentioned conditioned inside the test function
test
--------------------------------------------------------------------------
``` ```````````````````````````````````````````````````````````````
**Solved code**
``` ```````````````````````````````````````````````````````````````
#!bin/bash
### 2. creating directory ~/recyclebin in home if not present
if [[ ! -d $HOME/recyclebin ]]
then
mkdir $HOME/recyclebin
#touch $HOME/.restore.info
fi
### Creating .restore.info file if file is not yet present in
### home directory
if [ -d $HOME/recyclebin ] && [ ! -e $HOME/.restore.info ]
then
touch $HOME/.restore.info
fi
if [ $# -eq 0 ]
then
echo "recycle: missing operand"
exit 1
fi
### 4. Test Conditions to check
testCondition() {
for arg in "$#"
do
file=$arg
###File Does Not Exist Error
if [ ! -e "$file" ]
then
echo "recycle: Cannot delete $file: No such file exists"
file="Error"
exit 2
###Directory Name provided
elif [ -d $file ]
then
echo "recycle: Cannot delete $file : Is a directory."
file="Error"
exit 3
###cannot delete any argument with recycle in it
elif [[ "${file}" =~ .*"recycle".* ]]
then
echo "recycle: Attempting to delete – operation aborted"
file="Error"
exit 4
fi
processRequest $file
done
}
processRequest(){
if [[ "$noChoice" = true ]]
then
recycle $file
elif [ "$iOption" = true ] && [ "$vOption" = true ]
then
echo "recycle: remove file '$file' ? [y/n] "
read response
case $response in
[yY]*)
recycle $file
echo "recycle: '$file' is removed";;
*)
continue ;;
esac
elif [ "$iOption" = true ]
then
read -p "recycle: remove file '$file' ? [y/n] " response
case $response in
[yY]*)
recycle $file
echo "recycle: '$file' is removed";;
*)
continue ;;
esac
elif [ "$vOption" = true ]
then
recycle $file
echo "removed '$file' to the Recycle Bin"
fi
}
### Assigning the values of flename, absolute path and inode to variable
### name, absolute_path and inode before sending it to recyclebin folder
recycle() {
# If no errors mv the file to the recyclebin folder and add to .restore.info file.
if [[ ! $file == "Error" ]]
then
name=$(basename $file) #bcz file can be entered with full path
path_cropped=$(readlink -e $file | cut -d"/" -f6-)
absolute_path="${HOME}/${path_cropped}"
inode=$(stat -c '%i' $file)
filename=$name"_"$inode
echo $filename:$absolute_path >> $HOME/.restore.info # saving filename:path/to/file in .restore.info
mv $file $HOME/recyclebin/$filename # movinf file as filename_inode to recyclebin
fi
}
recFolder() {
for arg in $*
do
dirPath=$(readlink -e "$arg")
if [ -d "$dirPath" ] # check if the current argument IS a directory
then
if [[ $(ls "$dirPath" | wc -l) -eq 0 ]] #check to see if current directory is empty
then
rmdir $dirPath
else #if not an empty directory
findCurPathList=$(find $dirPath) # to find all the subdirectories and files list inside directory
for file in $findCurPathList
do
if [[ -f "$file" ]] #if it is a file
then
processRequest "$file"
fi
done
#-----------------------------------------------Now in previous loop, once all the files are removed and saved in
#recyclebinfolder and in .recycle.info file. Now delete the
#empty subdirectories in second loop
for args1 in $findCurPathList
do
if [[ -d $args1 ]]
then
if [[ $(ls $args1 | wc -l) -eq 0 ]]
then
rmdir $args1
fi
fi
done
#if [[ $(ls "$arg" | wc -l) -eq 0 ]] #check to see if current directory is empty
#then
# rmdir $dirPath
#fi
fi
else # if NOT a directory then this executes
echo "recycle: not a directory"
fi
done
}
###--------------------Starts from here, after checking dir if exists or not--------------------------------------
###Declaring variables which further fulfills condition to act as i, v, r commands
###as i = iOption; v = vOption; no command = noChoice and recycle files recursively
### = r or R
noChoice=true
iOption=false
vOption=false
removeFolder=false
while getopts ivrR opt
do
case $opt in
i)
iOption=true
noChoice=false;;
v)
vOption=true
noChoice=false;;
r)
removeFolder=true;;
R)
removeFolder=true;;
*)
echo "recycle: invalid input"
exit 1;;
esac
done
shift $(($OPTIND - 1))
### Now checking if -r or -R is passed as an argument and the passed in file argument
### is either directory or existing file to continue
if [[ "$removeFolder" == true ]]
then
for arg in "$#"
do
inputArg=$arg
if [[ -d $inputArg || -e $inputArg ]] # if the user pass -r request but the argument could either be
#a directory o a file not directory
then
argList=$(find "$inputArg")
recFolder "$argList"
else
echo "recycle: $inputArg does not exist!"
fi
done
else
### CAlling the test function to test all the mentioned conditioned inside the test function
testCondition "$#"
fi
A few months back, I installed a utility on my mac so that instead of typing something like this:
vim /type/path/to/the/file
I could just type:
v file
9 times out of 10 it would guess the right file based on the past history, similar to the way autojump works. And instead of typing in vim I can just type the letter v.
I can't remember how I set this up though. It still works on my mac but I don't see anything in my .bash_profile that shows how I did that.
I'm trying to get this to work on my linux box.
This can be found here
https://github.com/rupa/v/blob/master/v
it should work in Linux too. It is a bash script that uses the viminfo
history file to fill in partial strings.
It can be installed on macOS with brew install v
Ah! I found the command with which. Here is the magical script. I can't determine where I got it.
#!/usr/bin/env bash
[ "$vim" ] || vim=vim
[ $viminfo ] || viminfo=~/.viminfo
usage="$(basename $0) [-a] [-l] [-[0-9]] [--debug] [--help] [regexes]"
[ $1 ] || list=1
fnd=()
for x; do case $x in
-a) deleted=1;;
-l) list=1;;
-[1-9]) edit=${x:1}; shift;;
--help) echo $usage; exit;;
--debug) vim=echo;;
--) shift; fnd+=("$#"); break;;
*) fnd+=("$x");;
esac; shift; done
set -- "${fnd[#]}"
[ -f "$1" ] && {
$vim "$1"
exit
}
while IFS=" " read line; do
[ "${line:0:1}" = ">" ] || continue
fl=${line:2}
[ -f "${fl/\~/$HOME/}" -o "$deleted" ] || continue
match=1
for x; do
[[ "$fl" =~ $x ]] || match=
done
[ "$match" ] || continue
i=$((i+1))
files[$i]="$fl"
done < "$viminfo"
if [ "$edit" ]; then
resp=${files[$edit]}
elif [ "$i" = 1 -o "$list" = "" ]; then
resp=${files[1]}
elif [ "$i" ]; then
while [ $i -gt 0 ]; do
echo -e "$i\t${files[$i]}"
i=$((i-1))
done
read -p '> ' CHOICE
resp=${files[$CHOICE]}
fi
[ "$resp" ] || exit
$vim "${resp/\~/$HOME}"
Screenshot of the my code
I am trying to make a shell program that tells me when a file has been created, when it has been modified, and when it has been deleted. I think I can solve this but my only issue is that I cant compare the stat values. It tells me that I have "too many arguments". Any help would be much appreciated :)
#!/bin/bash
run=yes
if [ -f $1 ]
then
while [ run=yes ]
do
time1=$(stat -c %y $1)
time2=$(stat -c %y $1)
if [ ! $time2 ]
then
echo "The file "$1" has been deleted."
run=no
elif [ $time2 -gt $time1 ]
then
echo "The file "$1" has been modified."
run=no
fi
done
else
while [ run=yes ]
do
sleep 2
if [ -f $1 ]
then
echo "The file "$1" has been created."
run=no
fi
done
fi
The output of static -c %y ... includes spaces, which is what the shell uses to separate arguments. When you then run:
if [ ! $time2 ]; then
This translates into something like:
if [ ! 2017-09-02 08:57:19.449051182 -0400 ]; then
Which is an error. The ! operator only expects a single argument. You could solve it with quotes:
if [ ! "$time2" ]; then
Or by using the bash-specific [[...]]] conditional:
if [[ ! $time2 ]]; then
(See the bash(1) man page for details on that second solution).
Separately, you're not going to be able to compare the times with -gt as in:
elif [ $time2 -gt $time1 ]
This (a) has the same problem as the earlier if statement, and (b) -gt can only be used to compare integers, not time strings.
If you were to use %Y instead of %y, you would get the time as an integer number of seconds since the epoch, which would solve all of the above problems.
The code is now working and I thought I would share the final result if anyone wanted to know.
#!/bin/bash
run=true
if [ -f $1 ]
then
while [ "$run" = true ]
do
time1=$(stat -c %Y $1 2>/dev/null)
sleep $2
time2=$(stat -c %Y $1 2>/dev/null)
if [ ! "$time2" ]
then
echo "The file "$1" has been deleted."
run=false
elif [ $time2 -gt $time1 ]
then
echo "The file "$1" has been modified."
run=false
fi
else
while [ "$run" = true ]
do
sleep 2
if [ -f $1 ]
then
echo "The file "$1" has been created."
run=false
fi
done
fi
I am using if statement with multiple condition in bash.
How can I reduce the following line syntax. So that it looks good from design point of you.
if [ "$1" != "-l" ] && [ "$1" != "-a" ] && [ "$1" != "-h" ] && [ "$1" != "" ] && [ "$1" = "-d" ] || [ "$1" = "-mv" ] || [ "$1" = "-dv" ] || [ "$1" = "-mr" ] || [ "$1" = "-dr" ];
Thanks
Use pattern matching.
if [[ $1 && $1 != -[lah] && $1 == -#(d|mv|dv|mr|dr) ]]; then
#(...) is an example of an extended pattern, which should be recognized by default inside [[ ... ]] in recent versions of bash. If you version is not so recent, add shopt -s extglob to the beginning of your script.
In fact, you can drop the $1 && $1 != -[lah] because its truth would be implied by the truth of $1 == -#(...).
if [[ $1 == -#(d|mv|dv|mr|dr) ]]; then
You could also just use a POSIX-compliant case statement:
case $1 of
-d|-mv|-dv|-mr|-dr) echo good option ;;
*) echo bad option ;;
esac
You can create 2 arrays for matching and non matching values and check if element $1 matches any element in the array or not like below.
nonmatch_array=( "-l" "-a" "-h" "" )
match_array=( "-d" "-mv" "-dv" "-mr" "-dr" )
if [ `echo ${match_array[#]} | grep "$1"` ] || ! [ `echo ${nonmatch_array[#]} | grep "$1"` ] ; then
echo "is in array"
else
echo "is not in array"
fi
Hope it should work for you.
First try to limit the length of the code on 1 line.
if [ [ "$1" != "-l" ]
&& [ "$1" != "-a" ]
&& [ "$1" != "-h" ]
&& [ -n "$1" ]
&& ( [ "$1" = "-d" ]
|| [ "$1" = "-mv" ]
|| [ "$1" = "-dv" ]
|| [ "$1" = "-mr" ]
|| [ "$1" = "-dr" ] ) ];
I added braces, to make clear what you mean with the or's.
Now you can combine all matches with a regular expression:
if [[ ! ("$a" =~ ^-(l|a|h|d|)$)
&& "$a" =~ ^-(mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
but reconsider what you are testing. The test will only be true when it matches -mv/-dv/-mr/-dr, so you do not need to test for the options lah.
if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
You can use a variable for extracting the options:
options="d|mv|dv|mr|dr"
if [[ "$a" =~ ^-(${options})$ ]]; then
echo "Yes $a matches"
fi
Everytime the code is becoming hard to read (and also for long code or repeating statements), you should consider using a function.
The next function is short, but hard to read:
options="d|mv|dv|mr|dr"
function checkoption1 {
[[ "$a" =~ ^-(${options})$ ]]
}
checkoption1 "$a" &&
echo "Yes $a matches"
I would choose for a slightly more verbose function. I will include your original tests for lah for showing the possibilities.
# checkoption return 0 for match,
# returns 1 for forbidden option
# returns 2 for undefined option
function checkoption2 {
case "$1" in
-d|-mv|-dv|-mr|-dr) return 0 ;;
-l|-a|-h|"") return 1;;
*) return 2;;
esac
}
checkoption2 "$a" &&
echo "Yes $a matches"
You should make some testruns before accepting your code.
I have made some tests with a small loop (now all answers together)
function checkoption1 {
[[ "$a" =~ ^-(${options})$ ]]
}
# checkoption return 0 for match,
# returns 1 for forbidden option
# returns 2 for undefined option
function checkoption2 {
case "$1" in
-d|-mv|-dv|-mr|-dr) return 0 ;;
-l|-a|-h|"") return 1;;
*) return 2;;
esac
}
for a in -mv mv -mvx -ms -mr -dr; do
if [[ ! ("$a" =~ ^-(l|a|h|)$)
&& "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
options="d|mv|dv|mr|dr"
if [[ "$a" =~ ^-(${options})$ ]]; then
echo "Yes $a matches"
fi
checkoption1 "$a" &&
echo "Yes $a matches"
checkoption2 "$a" &&
echo "Yes $a matches 2"
done
I need a way of hashing a existing filename with a passphrase (ASCII string) but being able to revert it back afterwards using the same passphrase.
I know that ciphers can do this - they are encrypting the string... But their output lenght is based on the filename lenght, which is exactly what I do not want... mainly because it sometimes doubles the file lenght, but the outputted strings are not allways compatible with the FS. Ex. "\n" in a filename.
To be clear, I did a lot of research and even wrote some scripts, but all of the solutions are either slow, or don't work for my application at all.
The Goal of this is to get a constant length filenames that can be all 'decrypted' at once using a single passphrase. Without the need of creating additional 'metadata-like' files.
I've gotten all the way around with my initial question. There seems to be only one solution to the problem above, and that is (as James suggested) Format-preserving encryption. Altough, as far as I can tell, there are no existing commands that do this.
So I did exactly what was my very first option, and that is hashing the filename, putting the hash and the filename into a plain file (one file per directory) and encrypting that file with a passphrase.
I'll post my code here. Though it's probably not the prettiest nor the most portable code, but It does the job and is (IMO) really simple.
#!/usr/bin/env bash
man="Usage: namecrypt [ -h ] [ -e || -d ] [ -F ] [ -D ] [DIRECTORY] [PASSPHRASE]\n
-h, --help display this message
-e, --encrypt encrypt the specified directory
-d, --decrypt decrypt the specified directory
-F, --files include files
-D, --dir include directories
[DIRECTORY] relative or absolute path to a directory/symbolic link
[PASSPHRASE] optional - specify the user passphrase on command line";
options=();
for Arg in "$#"; do
if [ "$Arg" == "-h" ] || [ "$Arg" == "--help" ]; then
echo -e "$man"; exit;
elif [ "$Arg" == "-e" ] || [ "$Arg" == "--encrypt" ]; then
options[0]="E";
elif [ "$Arg" == "-d" ] || [ "$Arg" == "--decrypt" ]; then
options[0]="D";
elif [ "$Arg" == "-F" ] || [ "$Arg" == "--files" ]; then
options[1]="${options[1]}F";
elif [ "$Arg" == "-D" ] || [ "$Arg" == "--dir" ]; then
options[1]="${options[1]}D";
elif [ -d "$Arg" ]; then
options[2]="$(realpath "$Arg")";
else
options[3]="$Arg";
fi;
done;
if [ "${options[0]}" == "" ]; then echo "No Mode specified!"; exit 1; fi;
if [ "${options[1]}" == "" ]; then options[1]="F"; fi;
if [ "${options[2]}" == "" ]; then echo "No such directory!"; exit 2; fi;
if [ "${options[3]}" == "" ]; then echo "Enter a passphrase: "; read options[3]; fi;
shopt -s nullglob dotglob;
function hashTarget
{
BASE="$(basename "$1")";
DIR="$(dirname "$1")/";
if [ -a "$1" ]; then
oldName="$BASE";
newName=$(echo "$oldName" | md5sum);
echo "$oldName||$newName" >> "$DIR.names";
mv "$1" "$DIR$newName";
else echo "Skipping '$1' - No such file or directory!";
fi;
}
function dehashTarget
{
BASE="$(basename "$1")";
DIR="$(dirname "$1")/";
[ -f "$DIR.names.cpt" ] && ccdecrypt -K "${options[3]}" "$DIR.names.cpt";
if [ -f "$DIR.names" ]; then
oldName="$BASE";
newName=$(grep "$oldName" "$DIR.names" | awk -F '|' '{print $1}');
[[ ! -z "${newName// }" ]] && mv "$1" "$DIR$newName";
else
echo "Skipping '$1' - Hash table not found!";
fi;
}
function mapTarget
{
DIR="$(dirname "$1")/";
for Dir in "$1"/*/; do
mapTarget "$Dir";
done;
for Item in "$1"/*; do
if ([ -f "$Item" ] && [[ "${options[1]}" == *"F"* ]]) ||
([ -d "$Item" ] && [[ "${options[1]}" == *"D"* ]]); then
if [ "${options[0]}" == "E" ]; then
hashTarget "$Item";
else
dehashTarget "$Item";
fi;
fi;
done;
[ "${options[0]}" == "D" ] && [ -f "$DIR.names" ] && rm "$DIR.names";
[ "${options[0]}" == "E" ] && [ -f "$DIR.names" ] && ccencrypt -K "${options[3]}" "$DIR.names";
}
mapTarget "${options[2]}";
Probably the only reason why it is so long, is because I didn't bother with any OOP, and I also did a lot of checks and steps to make sure that most of the time no names get mangled and can't be restored - user error can still cause this.
This is the command used to encrypt the hash-table files: CCrypt