please simplify - ksh delete all files except first one per 7 days period, and give count - find

I want to delete all files in directory $fdir, except the first one, for each 7 days time period.
Then, I want to report how many files were deleted.
I came up with following:
days=365
fcount=0
while (( days > 7 ));do
# Get all files grouped per week, remove all except the first one.
fcountnw=$(
find $fdir -name '*.log' \
-mtime -$(( days )) \
-mtime +$(( days - 8 )) \
-printf "%C# %p\n" |
sort | cut -f2 -d " " |
tail -n+2 | xargs rm 2>/dev/null && echo '.' | wc -c
)
fcount=$(( fcount+ fcountnw))
(( days = days - 7 ))
done
echo $fcount
However, find seems to be quite slow. I know exactly in which directory to be, so it possible to do this in a simpler way - e.g. use ls instead?
Any input welcome!!

Why not combine ls with find to eliminate your sort and use an inner while loop instead of xargs
find $fdir -name '*.log' \
-mtime -$(( days )) \
-mtime +$(( days - 8 )) \
-exec ls -1rt {} + |
tail -n+2 | while read f; do
rm $f 2>/dev/null
fcount=$(( fcount + 1 ))
done

Related

iterate over stdin fish (context: filter music files by genre grep)

I have this:
for file in **/*.ogg;
if ffprobe "$file" 2>&1 | sed -E -n 's/^ *GENRE *: (.*)/\1/p' | grep -q "$argv";
echo "$file"
else
end
end
but I would like to turn it into a function which will take a list of filenames as standard-input:
$ find . -maxdepth 1 -not -type d -exec du -h {} + | cut -f2 | filterByGenre Classical
You could do
function filterByGenre
while read line
do stuff with $line
end
end
or
function filterByGenre
set listOfLines (cat)
for line in $listOfLines
do stuff with $line
end
end

Split results of du command by new line

I have got a list of the top 20 files/folders that are taking the most amount of room on my hard drive. I would like to separate them into size path/to/file. Below is what I have done so far.
I am using: var=$(du -a -g /folder/ | sort -n -r | head -n 20). It returns the following:
120 /path/to/file
115 /path/to/another/file
110 /file/path/
etc.
I have tried the following code to split it up into single lines.
for i in $(echo $var | sed "s/\n/ /g")
do
echo "$i"
done
The result I would like is as follows:
120 /path/to/file,
115 /path/to/another/file,
110 /file/path/,
etc.
This however is the result I am getting:
120,
/path/to/file,
115,
/path/to/another/file,
110,
/file/path/,
etc.
I think awk will be easier, can be combined with a pipe to the original command:
du -a -g /folder/ | sort -n -r | head -n 20 | awk '{ print $1, $2 "," }'
If you can not create a single pipe, and have to use $var
echo "$var" | awk '{ print $1, $2 "," }'

using find with a loop returning files with spaces in their names

Using Cygwin on Windows 10, I am trying to find files in one directory (dir1) that are not in another (dir2), regardless of the file path
The idea is to loop through all files in dir1 and, for each, launch a find command in dir2 and display only the missing files:
for f in `ls -R /path/to/dir1` ; do
if [ $( find /path/to/dir2 -name "$f" | wc -l ) == 0 ] ; then
echo $f
fi
done
The problem is that some of the file names have spaces in them and this is causing the find command to fail
Any ideas?
Could you do this with find and comm? Something like the following should print files in dir1 which aren't in dir2.
comm -23 <(find dir1 -type f -printf '%f\n' | sort -u) <(find dir2 -type f -printf '%f\n' | sort -u)
It works with spaces, too:
$ mkdir dir1 dir2
$ touch dir1/foo dir1/bar
$ touch dir2/foo dir2/baz
$ touch dir1/'foo bar'
$ comm -23 <(find dir1 -type f -printf '%f\n' | sort -u) <(find dir2 -type f -printf '%f\n' | sort -u)
./bar
./foo bar
For real safety, you should use NUL-terminated strings, so filenames with newlines in will work.
comm -z23 <(find dir1 -type f -printf '%f\0' | sort -uz) <(find dir2 -type f -printf '%f\0' | sort -uz) | xargs -0 printf '%s\n'

Using grep with sed and writing a new file based on the results

I'm very new to some of the command line utilities and have been looking for a while for a command that would accomplish my goal.
The goal is to find files that contain a string of text, replace it with a new string, and then write the results to a file that is named the same as the original, but in a different directory.
Obviously this is not working, so I am asking how you who know about this stuff would go about it.
grep -rl 'stringToFind' *.* | sed 's|oldString|newString|g' < fileNameFromGrep > ./new/fileNameFromGrep
Thanks for your input!
John
for f in "`find /YOUR/SEARCH/DIR/ROOT -type f -exec fgrep -l 'stirngToFind' \{\} \;`" ; do
sed 's|oldString|newString|g' < "${f} > ./new/"${f}
done
Will do it for you.
If you have spaces in filenames:
OLDIFS=$IFS
IFS=''
find /PATH -print0 -type f | while read -r -d $'' file
do
fgrep -l 'stirngToFind' "$file" && \
sed 's|oldString|newString|g' < "${file} > ./new/"${file}
done
IFS=$OLDIFS
#!/bin/bash
for file in *; do
if grep -qF 'stringToFind' "$file"; then
sed 's/oldString/newString/g' "$file" > "./new/$file"
fi
done
for file in path/to/dir/*
do
grep -q 'pattern' "$file" > /dev/null
if [ $? == 0 ]; then
sed 's/oldString/newString/g' "$file" > /path/to/newdir/"$file"
fi
done
You try:
sed -ie "s/oldString/newString/g" \
$(grep -Rsi 'pattern' path/to/dir/ | cut -d: -f1)
sed:
i in_place
e exec other command or script
grep:
R recursive
s Suppress error messages
i ignore case sensitive

How do I find the largest 10 files in a given directory?

How do I find the largest 10 files in a given directory, with Perl or Bash?
EDIT:
I need this to be recursive.
I only want to see large files, no large directories.
I need this to work on Mac OS X 10.6 ('s version of find).
This prints the 10 largest files recursively from current directory.
find . -type f -printf "%s %p\n" | sort -nr | awk '{print $2}' | head -10
$ alias ducks
alias ducks='du -cs * |sort -rn |head -11'
This is a way to do it in perl. (Note: Non-recursive version, according to earlier version of the question)
perl -wE 'say for ((sort { -s $b <=> -s $a } </given/dir/*>)[0..9]);'
However, I'm sure there are better tools for the job.
ETA: Recursive version, using File::Find:
perl -MFile::Find -wE '
sub wanted { -f && push #files, $File::Find::name };
find(\&wanted, "/given/dir");
#files = sort { -s $b <=> -s $a } #files;
say for #files[0..9];'
To check file sizes, use e.g. printf("%-10s : %s\n", -s, $_) for #files[0..9]; instead.
How about this -
find . -type f -exec ls -l {} + | awk '{print $5,$NF}' | sort -nr | head -n 10
Test:
[jaypal:~/Temp] find . -type f -exec ls -l {} + | awk '{print $5,$NF}' | sort -nr | head -n 10
8887 ./backup/GTP/GTP_Parser.sh
8879 ./backup/Backup/GTP_Parser.sh
6791 ./backup/Delete_HIST_US.sh
6785 ./backup/Delete_NORM_US.sh
6725 ./backup/Delete_HIST_NET.sh
6711 ./backup/Delete_NORM_NET.sh
5339 ./backup/GTP/gtpparser.sh
5055 ./backup/GTP/gtpparser3.sh
4830 ./backup/GTP/gtpparser2.sh
3955 ./backup/GTP/temp1.file