searching for file unix script - bash

My script is as shown:
it searches for directories and provides info on that directory, however I am having trouble setting exceptions.
if [ -d "$1" ];
then
directories=$(find "$1" -type d | wc -l)
files=$(find "$1" -type f | wc -l)
sym=$(find "$1" -type l | wc -l)
printf "%s %'d\n" "Directories" $directories
printf "%s %'d\n" "Files" $files
printf "%s %'d\n" "Sym links" $sym
exit 0
else
echo "Must provide one argument"
exit 1
fi
How do I make it so that if I search for a file it tells me that a directory needs to be inputted? I'm stuck on it, I've tried test commands but I don't know what to do.

You're missing your shebang in the first line of your script:
#!/bin/bash
I get correct results from your script if I add it:
Directories 1,991
Files 13,363
Sym links 0
You may have to set the correct execution permissions also chmod +x scriptname.sh?
Entire script looks like this:
#!/bin/bash
if [ -z "$1" ];
then
echo "Please provide at least one argument!"
exit 1
elif [ -d "$1" ];
then
directories=$(find "$1" -type d | wc -l)
files=$(find "$1" -type f | wc -l)
sym=$(find "$1" -type l | wc -l)
printf "%s %'d\n" "Directories" $directories
printf "%s %'d\n" "Files" $files
printf "%s %'d\n" "Sym links" $sym
exit 0
else
echo "This is a file, not a directory"
exit 1
fi

Related

Passing ls command to a for loop breaks when trying to use command line arguments

Im writing a simple script to list all files in a directory and whether each file is in fact a file or if it is a directory. If it is a directory then it outputs how many files are in the directory.
#!/bin/bash
for filename in $(ls)
do
if [ -f "$filename" ]
then
printf "$filename - file\n"
fi
if [ -d "$filename" ]
then
count=$(ls "$filename" | wc -l)
printf "$filename - directory $count files\n"
fi
done
This works perfectly fine. But if I try to pass a command line argument (directory name) to ls then the script doesn't work. Does anyone know what causes this to break. Example below.
#!/bin/bash
for filename in $(ls $1)
do
if [ -f "$filename" ]
then
printf "$filename - file\n"
fi
if [ -d "$filename" ]
then
count=$(ls "$filename" | wc -l)
printf "$filename - directory $count files\n"
fi
done
$filename exists in directory/$filename. And you are check $filename in current (./) directory.
You should check against directory/$filename
if [ -z $1 ]; then
echo USAGE: basename $0 directory
exit
else
directory=$1
fi
...
for ...
if [ -f "$directory/$filename" ]; then
...
...
When you are passing directory as argument you shouldn't check files $filename but $1/$filename.
If you are sure that there will always be an argument you should use something like:
#!/bin/bash
for filename in $(ls "$1")
do
if [ -f "$1/$filename" ]
then
printf "$1/$filename - file\n"
fi
if [ -d "$1/$filename" ]
then
count=$(ls "$1/$filename" | wc -l)
printf "$1/$filename - directory $count files\n"
fi
done
If dirname as argument is optional you should check if there is argument and process as you want. My suggestion:
#!/bin/bash
if [ -z ${1+x} ];
then
echo "No argument";
else
echo "There is argument";
cd $1;
fi
for filename in $(ls)
do
if [ -f "$filename" ]
then
printf "$filename - file\n"
fi
if [ -d "$filename" ]
then
count=$(ls "$filename" | wc -l)
printf "$filename - directory $count files\n"
fi
done

How to store the grep output into a variable inside a loop?

I would like to count the number of outputs produced by this loop
cd /System/Library/Extensions
find *.kext -prune -type d | while read d; do
codesign -v "$d" 2>&1 | grep "invalid signature"
done
How can I store or count the outputs? If tried with arrays, counters etc. but it seems I can't get anything outside of that loop.
To obtain the number of lines produced by the while loop, the wc word count can be used
cd /System/Library/Extensions
find *.kext -prune -type d | while read d; do
codesign -v "$d" 2>&1 | grep "invalid signature"
done | wc -l
wc -l the -l option counts the number of lines in the input, which is piped to the output of while
Now if you need to count the number of grep outputs in each iteration of the while loop, the -c option of grep would be usefull.
cd /System/Library/Extensions
find *.kext -prune -type d | while read d; do
codesign -v "$d" 2>&1 | grep -c "invalid signature"
done
-c Suppress normal output; instead print a count of matching lines
for each input file
classical difficulty in subshell is to pass variables back.
here one way to get this information back :
cd /System/Library/Extensions
RESULT=$(find *.kext -prune -type d | {
# we are in a sub-subshell ...
GCOUNT=0
DIRCOUNT=0
FAILDIR=0
while read d; do
COUNT=$(codesign -v "$d" 2>&1 | grep -c "invalid signature")
if [[ -n $COUNT ]]
then
if [[ $COUNT > 0 ]]
then
echo "[ERROR] $COUNT invalid signature found in $d" >&2
GCOUNT=$(( $GCOUNT + $COUNT ))
FAILDIR=$(( $FAILDIR + 1 ))
fi
else
echo "[ERROR] wrong invalid signature count for $d" >&2
fi
DIRCOUNT=$(( $DIRCOUNT + 1 ))
done
# this is the actual result, that's why all other output of this subshell are redirected
echo "$DIRCOUNT $FAILDIR $GCOUNT"
})
# parse result integers separated by a space.
if [[ $RESULT =~ ([0-9]+)\ ([0-9]+)\ ([0-9]+) ]]
then
DIRCOUNT=${BASH_REMATCH[1]}
FAILDIR=${BASH_REMATCH[2]}
COUNT=${BASH_REMATCH[3]}
else
echo "[ERROR] Invalid result format. Please check your script $0" >&2
fi
if [[ -n $COUNT ]]
then
echo "$COUNT errors found in $FAILDIR/$DIRCOUNT directories"
fi

Bash script loop through subdirectories and write to file

I have no idea I have spent a lot of hours dealing with this problem. I need to write script. Script should loop recursively through subdirectories in current directory. It should check files 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 subdirecotries don't include subdirectories in turn.
I am confused about this. Because it doesn't work as I expect. It will take less than 5 minutes to write this on any programming language for my.
Please help to solve this problem , because I have no idea how to do this.
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
I believe that this does what you want:
find . -type d -exec env d={} bash -c 'out=Shortlist; [ $(ls "$d" | wc -l) -ge 10 ] && out=Biglist; { echo "--$d"; ls "$d"; echo; } >>"$out"' ';'
If we don't want either to count subdirectories to the cut-off or to list them in the output, then use this version:
find . -type d -exec env d={} bash -c 'out=Shortlist; [ $(ls -p "$d" | grep -v "/$" | wc -l) -ge 10 ] && out=Biglist; { echo "--$d"; ls -p "$d"; echo; } | grep -v "/$" >>"$out"' ';'

Count the deleted files Shell script

Can you tell me how can you count the files with the extension ".txt" you delete from a folder? Shell script in Unix
Thank you for your answer :)
I tried to delete them this way :
deleted=0
while read line
do
if test -d "$line"
then
for i in "$line"/*
do
if test -f "$i"
then
deleted=`ls -l $line |grep "*.o" | wc -l`
echo "From: " $line " I deleted : " $deleted
find . -type f -name "*.o" -exec rm -f {} \;
else
echo "Not file " $i
fi
done
else
echo "NOT a directory!"
fi
done
Try doing this :
LANG=C rm -v *.txt | grep -c "^removed "
An answer - though not necessarily the right one:
files=*.txt
ls -1 "$files" | wc -l
rm "$files"
Ruth

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