Suffix subdirectory name with number of files underneath it - directory

I have subdirectories a b c. For various obscure reasons, I would like to count all files recursively underneath these and only for maxdepth=1 mindepth=1 suffix this first layer of subdirectories with the file count down to the bottom of each subdirectory tree (no limit).
So if a and its subdirectories have 23 files, b...64 and c...82 I will end up with subdirectories renamed as
a_23
b_64
c_82
I have a routine to count recursively:
function count_all_files () {
echo "enter directory"
find "$1" -type f | wc -l
}
but am at a loss how to construct a find -exec operation to rename as I need.
Something like this pseudo code.
find . -type d -mindepth 1 -maxdepth 1 "*" -exec $(count_all_files {}) && [suffix dir name]
Grateful for thoughts. Needs to work with directories containing spaces too.

This seems to be working. I have amended it so it always makes a clean update eg if you add new files.
function label_subdirectories_number_files () {
for file in *_my_dir_count_* ; do rename 's/_my_dir_count_.*//g' "$file" ; done
find . -type d -mindepth 1 -maxdepth 1 -name '*' -exec bash -c 'cd {} \
&& number_of_files=$(find . -type f | wc -l) && directory=$(pwd) \
&& directory="${directory## }" && read -r number_of_files <<< "$number_of_files" \
&& new_directory="$directory""_my_dir_count_""$number_of_files" && \mv "$directory" "$new_directory" ' &> /dev/null 2>&1 \;
}
This variation does selected number of lower subdirectories too in case you want a quick eyeball test of lower level counts.
function label_subdirectories_number_files_many () {
echo "enter number of levels to scan"
for file in *_my_dir_count_* ; do rename 's/_my_dir_count_.*//g' "$file" &> /dev/null 2>&1 ; done
for zcount in $(seq 1 "$1") ; do
echo "level = $zcount out of $1 "
find . -type d -mindepth $zcount -maxdepth $zcount -name '*' -exec bash -c 'cd {} \
&& number_of_files=$(find . -type f | wc -l) && directory=$(pwd) \
&& directory="${directory## }" && read -r number_of_files <<< "$number_of_files" \
&& new_directory="$directory""_my_dir_count_""$number_of_files" && \mv "$directory" "$new_directory" ' &> /dev/null 2>&1 \;
done
}

Related

Unix SSH : Find files with different path on two servers

I have server A & Server B . I want to file find command on both server but with different path .
Currently i created below code to do so :
dir1=( $DATA_DIR/sdfgv $DATA_DIR/1wefgg $DATA_DIR/3fdsevg );
dir2=( $DATA_DIR/asdf $DATA_DIR/sdfewfT $DATA_DIR/efergvfw );
timestamp=$(date +%Y%m%d%H%M%S);
report_name=Audit_Report_${timestamp}.txt
uname=xyz
server=( serv1 serv2);
for j in ${server[#]};
do {
if [ "$j" == "serv1 " ]
then
for i in ${dir1[#]};
do {
Size=`ssh -q $uname#$j "find $i -type f -mtime +1 -name '*.gz' -printf '%s + ' | dc -e0 -f- -ep"`;
echo " $j $i $Size "
}
done
else
for i in ${dir2[#]};
do {
Size=`ssh -q $uname#$j "find $i -type f -mtime +1 -name '*.gz' -exec du -k {} \; | awk '{ total += $ 1} END{print total/1024;}'"`;
echo " $j $i $Size "
}
done
fi
}
done
This code works pretty good but i want something that can be generic without if else on server name .
I dont want to use if else for server name .
Both server have different directory path to search for
Please come up with some suggestions .
Thank You !
Bash functions would help. Perhaps one for determining which directory to use for which server, and then one for executing the find command. Something like this (pseudo-code, untested):
getDirs() {
if [ $1 == 'server1' ]; then
echo $dir1
fi
if [ $1 == 'server2' ]; then
echo $dir2
fi
}
findFiles() {
local srv=$1
shift
local dir=$1
shift
local findArgs=$#
echo $(ssh -q $uname#$srv "find $dir $findArgs")
}
for srv in ${server[#]};
do
dirs=$(getDirs $srv)
for d in $dirs
do
findFiles $srv $d -type f -mtime +1 -name '*.gz'
done
done
Your sample does different things with the find results, so you will still need to add logic to handle that (could just be an if statement inside the loops maybe..)

How to calculate total size of all css,js and html pages separately uing shell script?

I have the following code in shell script
find -name "*.css" -exec -printf '%16f Size: %6s\n'
This gives me the file size of every css file. How do I modify this to get the added sum of all the file sizes ?
You could use awk:
find . -name "*.css" -type f -printf '%s\n' | awk '{ tot+=$0 } END { print tot }'
Or in pure bash:
total=0
while read -r s;
do
total=$(( total+s ))
done < <(find . -name "*.css" -type f -printf '%s\n')
echo $total
In 2 steps:
1) ll *css | tr -s " " > filename.txt
2) awk 'BEGIN {x=0} {x+=$5} END {print x}' filename.txt

Unix Loop if Condition and exit comand

I am facing an issue, I have to delete files from some folders given in Path.lst,
The entire script is working fine but when some wrong path is given in Path.lst the script does exits out of the loop and perform no operation on the next paths.
But the last line
echo -e "\n ENDING SCRIPT SUCCESSFULLY ON `date` " >> $LOG_FILE
gets executed because exit 1 is not working in this part
if [ ! -d $path ]
then
echo -e "\nERROR :$path IS INVALID." >> $LOG_FILE
echo -e "\nENDING SCRIPT WITH ERRORS ON `date`" >> $LOG_FILE
exit 1
---------------------------------------------------------------------------------------
THE SCRIPT IS LIKE :
echo -e "\nSTARTING SCRIPT ON `date`">> $LOG_FILE
if [ $1 -gt 0 ]
then
DAYS_BFOR="$1"
else
echo -e "\nERROR :Please pass a single positive integer to the script" >>$LOG_FILE
echo -e "\nENDING SCRIPT WITH ERRORS ON `date` " >> $LOG_FILE
exit
fi
cat Path.lis | sed 's|^PATH[0-9]*=||g' | while read path
do
if [ ! -d $path ]
then
echo -e "\nERROR :$path IS INVALID." >> $LOG_FILE
echo -e "\n ENDING SCRIPT WITH ERRORS ON `date` " >> $LOG_FILE
exit 1
else
echo -e "\nFILES DELETED FROM THE "$path" DIRECTORY --" >> $LOG_FILE
find $path -type f -mtime +$DAYS_BFOR -printf "%TY-%Tm-%Td %kKB %p\n" | column -t | sed "s|"$path"||g" >> $LOG_FILE 2>&1
file_count=`find $path -type f -mtime +$DAYS_BFOR | wc -l`
if [ $file_count -ge 1 ]
then
find $path -type f -mtime +$DAYS_BFOR | xargs rm 2>>$LOG_FILE 2>&1
fi
fi
done
echo Exit Status : $?
echo -e "\n ENDING SCRIPT SUCCESSFULLY ON `date`" >> $LOG_FILE
Please help and explain the reason as well.
If you only want the "ENDING SCRIPT SUCCESSFULLY" message to appear if files were successfully deleted, not if an invalid path was given you could just move the last two echo lines up to the end of the else statement like this:
else
echo -e "\nFILES DELETED FROM THE "$path" DIRECTORY --" >> $LOG_FILE
find $path -type f -mtime +$DAYS_BFOR -printf "%TY-%Tm-%Td %kKB %p\n" | column -t | sed "s|"$path"||g" >> $LOG_FILE 2>&1
file_count=`find $path -type f -mtime +$DAYS_BFOR | wc -l`
if [ $file_count -ge 1 ]
then
find $path -type f -mtime +$DAYS_BFOR | xargs rm 2>>$LOG_FILE 2>&1
fi
echo Exit Status : $?
echo -e "\n--------------------------- ENDING SCRIPT SUCCESSFULLY ON `date` ----------------------------------" >> $LOG_FILE
fi
done
If you want to just skip to the next item in the Path.lis file then just remove the exit statement from the first loop. That way it will continue to execute the script until all the lines in the file have been read, and just show an error if the current file is not a valid path.

Remove duplicate jars in a directory

I have a script to remove lower version jars files in a directory.
#!/bin/bash
#Script to remove lower version jar files.
for PREFIX in `ls *.jar|sed 's/-[0-9\.\0-9\.a-zA-Z]*\.jar//g'|uniq -d`; do
for FILE in `ls -r ${PREFIX}*|sed '1d'`; do
echo " $FILE"
rm $FILE
done
done
It has a bug.
I have below list of Duplicate jar files in a directory.
xyz-1.1.jar
xyz-1.1.1.jar
abc-1.6.jar
abc-1.3.jar
abc-xyz-pqr-1.9.6.jar
abc-xyz-pqr-1.9.2.jar
xyz-tom.jar
xyz-tom-20120423.jar
xyz-tom-20120410.jar
abc-toolkit-1.6-runtime-5.2.0.jar
abc-toolkit-1.6-runtime-5.0.0.jar
The bug is with xyz pattern jar files.
BUG:
Script is removing xyz-1.1.1.jar file instead of xyz-1.1.jar
Script is removing xyz-tom-20120423.jar and xyz-tom-20120410.jar files.
#!/bin/bash
if [ $# == 0 ]; then
dir='.'
elif [ $# == 1 ]; then
dir=$1
else
echo "Usage: $0 [dir]";
exit 1;
fi
for lib in `find $dir -name '*.jar'`; do
for class in `unzip -l $lib | egrep -o '[^ ]*.class$'`; do
class=`echo $class | sed s/\\\\.class// | sed s/[-.\\/$]/_/g`
existing=$( eval "echo \$CLS_${class}" )
if [ -n "$existing" ]; then echo "$lib $existing"; fi
eval CLS_${class}="\"${lib} ${existing}\""
done
done | sort | uniq -c | sort -nr
I find this code here

Unix script to delete file if it contains single line

Consider I have a file abcde.txt which may contain one or more lines of text. I want a script that will DELETE the file if it contains single line.
Something like, if 'wc -l abscde.txt' = 1 then rm abscde.txt
My system : Solaris
Here's a simple bash script:
#!/bin/bash
LINECOUNT=`wc -l abscde.txt | cut -f1 -d' '`
if [[ $LINECOUNT == 1 ]]; then
rm -f abscde.txt
fi
delifsingleline () {
if [ $(cat $1 | wc -l) = "1" ]
then
echo "Deleting $1"
echo "rm $1"
fi
}
Lightly tested on zsh. Should work on bash as well.
This is (mostly) just a reformat of Ben's answer:
wc -l $PATH | grep '^1 ' > /dev/null && rm -f $PATH

Resources