I am trying to grep some pattern in a file set under a folder like below
Where on the output I have to perform remaining operation.
The output main.log is coming so huge almost 50k lines ,as the files starting with server02.log are almost 30 to 40 in number . The script based on this output is taking forever to complete.
Is there a way that I can only take files name starting with server02.log. and generated between time
20:00:00 and 21:00:00
ls -lrth server02.log.*
-rw-r--r-- 1 user user 1.9M Apr 15 20:20 server02.log.2020
-rw-r--r-- 1 user user 1.7M Apr 15 20:30 server02.log.2030
-rw-r--r-- 1 user user 1.6M Apr 15 20:41 server02.log.2041
-rw-r--r-- 1 user user 1.9M Apr 15 20:50 server02.log.2050
-rw-r--r-- 1 user user 2.1M Apr 15 21:00 server02.log.2100
-rw-r--r-- 1 user user 1.4M Apr 15 21:10 server02.log.2110
-rw-r--r-- 1 user user 1.9M Apr 15 21:20 server02.log.2120
-rw-r--r-- 1 user user 656K Apr 15 21:29 server02.log.2129
-rw-r--r-- 1 user user 4.6M Apr 15 21:40 server02.log.2140
-rw-r--r-- 1 user user 1.9M Apr 15 21:50 server02.log.2150
-rw-r--r-- 1 user user 1.7M Apr 15 21:59 server02.log.2159
-rw-r--r-- 1 user user 724K Apr 15 22:09 server02.log.2209
-rw-r--r-- 1 user user 1.3M Apr 15 22:20 server02.log.2220
-rw-r--r-- 1 user user 1.1M Apr 15 22:29 server02.log.2229
-rw-r--r-- 1 user user 1.7M Apr 15 22:41 server02.log.2241
-rw-r--r-- 1 user user 1.5M Apr 15 22:49 server02.log.2249
-rw-r--r-- 1 user user 2.4M Apr 15 23:01 server02.log.2301
-rw-r--r-- 1 user user 1.4M Apr 15 23:10 server02.log.2310
-rw-r--r-- 1 user user 585K Apr 15 23:19 server02.log.2319
-rw-r--r-- 1 user user 858K Apr 15 23:30 server02.log.2330
-rw-r--r-- 1 user user 892K Apr 15 23:40 server02.log.2340
-rw-r--r-- 1 user user 698K Apr 15 23:49 server02.log.2349
grep -E "###Update |###Initiate |###Re-Initiate " server02.log.* >> main.log
from the comments I made the change to my code as below
#!/bin/bash
DIR="."
d=$(date +%Y-%m-%d);
log_dir="logs/$d"
PREFIX="$log_dir/srv_02.log"
#PREFIX="srv_02.log"
echo "prefix value is $PREFIX"
START_HOUR="06"
for F in "$( find "$DIR" -name "${PREFIX}*" -printf '%Tc %p\n' | grep "\ ${START_HOUR}:" )"; do
echo "F value is $F"
grep -E "###Update |###Initiate |###Re-Initiate" "$F" >> main.log
done
error:
prefix value is logs/2021-04-16/srv_02.log
find: warning: Unix filenames usually don't contain slashes (though pathnames do). That means that '-name `logs/2021-04-16/srv_02.log*'' will probably evaluate to false all the time on this system. You might find the '-wholename' test more useful, or perhaps '-samefile'. Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ `logs/2021-04-16/osbpd_srv_02.log*''.
F value is
grep: : No such file or directory
This solution looks for files in the given directory, created during the specified hour with names matching the given prefix.
#!/bin/bash
d=$(date +%Y-%m-%d)
DIR="logs/$d/$log_dir"
PREFIX="srv_02.log"
#PREFIX=server02.log
echo "prefix value is $PREFIX"
START_HOUR="06"
for F in "$( find "$DIR" -name "${PREFIX}*" -printf '%TY-%Tm-%Td\n' | grep "\ ${START_HOUR}:" )"; do
echo "$F"
# grep -E "###Update |###Initiate |###Re-Initiate Assignment Milestone|###Complete Assignment Milestone|###Cancel Assignment Milestone|###Suspend Assignment Milestone|###Resume Assignment Milestone" "$F" >> main.log
done
Related
Is there any way to take away the owner's permission to read a file in macOS? I know there's no reason to do this but I have to for school and I can't find an answer anywhere. Removing my write permission works fine but when I try to remove my read permission it automatically give me my read and write permissions back. As you can see in the console when I use chmod -v -v (extra verbose) it shows the correct permissions it should be changed to but then when checking afterwards they havent changed into that...
thijs#Thijss-MacBook-Air-2 week6 % ls -l
total 16
-rw----r-- 1 thijs staff 12 Oct 11 21:10 greeting.txt
-rw-r--r-- 1 thijs staff 0 Oct 11 21:10 hello.txt
-rw------- 1 thijs staff 15 Oct 11 21:11 weather.txt
thijs#Thijss-MacBook-Air-2 week6 % chmod -v -v u-w weather.txt
weather.txt: 0100600 [-rw------- ] -> 0100400 [-r-------- ]
thijs#Thijss-MacBook-Air-2 week6 % ls -l
total 16
-rw----r-- 1 thijs staff 12 Oct 11 21:10 greeting.txt
-rw-r--r-- 1 thijs staff 0 Oct 11 21:10 hello.txt
-r-------- 1 thijs staff 15 Oct 11 21:11 weather.txt
thijs#Thijss-MacBook-Air-2 week6 % chmod -v -v u-r weather.txt
weather.txt: 0100400 [-r-------- ] -> 0100000 [---------- ]
thijs#Thijss-MacBook-Air-2 week6 % ls -l
total 16
-rw----r-- 1 thijs staff 12 Oct 11 21:10 greeting.txt
-rw-r--r-- 1 thijs staff 0 Oct 11 21:10 hello.txt
-rw------- 1 thijs staff 15 Oct 11 21:11 weather.txt
I have the following find command that searches all subdirectories and lists those folders that contain a *.RAR AND a *.MKV file.
find -type d -exec sh -c '[ -f "$0"/*.rar ] && [ -f "$0"/*.mkv ]' '{}' \; -print | sort
What I want to do now is to delete the *.MKV file from those directories.
For example, the above command finds FILEA.RAR and FILEB.MKV and lists the directory as DIRECTORY_CHARLIE. I would like to be able to have the above code, also delete the FILEB.MKV file, well delete the found MKV file from each directory that had both file types.
To start, I've created "_TestDir" with the following subfolders:
#useroneserver ~/files/_TestDir $ ls -all
drwxr-xr-x 2 userone userone 50 Feb 27 19:31 Folder01
drwxr-xr-x 2 userone userone 50 Feb 27 19:32 Folder02
drwxr-xr-x 2 userone userone 50 Feb 27 19:32 Folder03
drwxr-xr-x 2 userone userone 50 Feb 27 19:33 Folder04
drwxr-xr-x 2 userone userone 50 Feb 27 19:34 Folder05
Each folder has 2 files, except Folder03, which only has one file.
userone#remoteserver ~/files/_TestDir $ ls Folder01 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:03 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:31 File1.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:30 FileA.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder02 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:04 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:32 File2.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:31 FileB.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder03 -all
drwxr-xr-x 2 userone userone 30 Mar 1 20:04 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:32 FileC.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder04 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:04 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:33 File4.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:33 FileD.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder05 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:05 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:34 File5.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:33 FileE.mkv
When I run the command in the original post, I get this:
userone#remoteserver ~/files/_TestDir $ find -type d -exec sh -c '[ -f "$0"/*.rar ] && [ -f "$0"/*.mkv ]' '{}' \; -print | sort
./Folder01
./Folder02
./Folder04
./Folder05
That is what I expect to see as the results, since folders 1, 2, 4 & 5 have a file of each of the extensions that I am looking for (*.rar & *.mkv), where as folder 3 only has one *.mkv file.
I have not tried to add any delete function since I have no clue where to start.
What I would like to happen is to be able to remove/delete the following
files:
FileA.mkv from Folder01
FileB.mkv from Folder02
FileD.mkv from Folder04
FileE.mkv from Folder05
Nothing gets deleted from Folder03 since it does not have a .RAR AND a .MKV file, it only has the .MKV. Hope this helps clarify.
Thank you for your assistance.
Regards.
You want to use xargs to run rm which will delete the files.
And define the replacement string, using the -I option of xargs.
Using your directory structure, you can do:
find -type d -exec sh -c '[ -f "$0"/*.rar ] && [ -f "$0"/*.mkv ]' '{}' \; -print | sort | xargs -I % sh -c "rm -f %/File?.mkv"
I took your exact find command, and added this:
| xargs -I % sh -c "rm -f %/File?.mkv"
Explanation
when find runs, it will output
./Folder01
./Folder02
./Folder04
./Folder05
Since xargs is used with the -I % option, it will run the command, replacing % with each directory (like in a loop, one by one). You could use another character than %, but avoid wildcard characters.
The command that xargs will run is sh -c "rm -f %/File?.mkv"
It will therefore do the following commands, in succession:
sh -c "rm -f Folder01/File?.mkv"
sh -c "rm -f Folder02/File?.mkv"
sh -c "rm -f Folder04/File?.mkv"
sh -c "rm -f Folder05/File?.mkv"
Obviously, you can adjust as required.
When I execute the ls -l -h command, I get an output as show by the image below.
How can the number of the items in a folder be included in the output?
Update
The current output looks like this
total 41M
-rw-r--r-- 1 root root 41M Dec 20 09:56 completed_projects.bson
-rw-r--r-- 1 root root 213 Dec 20 09:57 completed_projects.metadata.json
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:22 contents
-rw-rw-r-- 1 adipster adipster 13 Jun 16 13:20 file.py
drwxrwxr-x 4 adipster adipster 4.0K Jun 16 13:22 folder
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:21 items
But I'll like to have another column indicating the number of items in a folder like this
total 41M
-rw-r--r-- 1 root root 41M Dec 20 09:56 completed_projects.bson
-rw-r--r-- 1 root root 213 Dec 20 09:57 completed_projects.metadata.json
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:22 contents 235
-rw-rw-r-- 1 adipster adipster 13 Jun 16 13:20 file.py
drwxrwxr-x 4 adipster adipster 4.0K Jun 16 13:22 folder 19
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:21 items 5
where the numbers at the extreme right represents the number of items in a folder
You can do something like this:
echo -n "Number of files in folder is: " && ls | wc -l && ls -l
ouptut should be something like this:
umber of files in folder is: 3
Total 279K
-rwxr-xr-x 1 user users 19K Jun 16 00:17 a
-rwxr-xr-x 1 user users 5K Jun 16 00:17 b
-rwxr-xr-x 1 user users 255K Jun 16 00:17 c
You can omit echo statement, just as a note -n is no new line flag.
sed has an option to execute the constructed replacement with /e.
We only count subdirs, looking at the first character
ls -l | sed -r 's/d(.*) ([^ ]*)/printf "d%s %-20s%s\n" "\1" \2 $(ls \2| wc -l)/e'
EDIT: Solution for directories with spaces in their name.
Parsing ls should be avoided. When you try to fix above cmmand for directory names with spaces, you might try
# Don't do this
ls -l | sed -r 's/d(.{,48}) (.*)/printf "d%s %-20s%s\n" "\1" "\2" $(ls "\2"| wc -l)/e'
It is time to write a script. Perhaps with find or something like
#/bin/bash
for i in *; do
printf "%-70s %s\n" "$(/bin/ls -ld "$i")" "$(/bin/ls -d "$i"/* 2>/dev/null| wc -l)"
done
The wc in the subdir will count wrong when filenames have newlines.
ls() { command ls "$#" | tee >(echo "$(wc -l) items"); }
That uses an output process substitution to run the little "echo" script on its stdin while also displaying stdin (thanks to tee). This way, you don't have to run ls twice.
Usual caveat: output will be incorrect when there's a file with a newline in the name.
I have a directory like this:
-rw-r--r-- 1 root root 0 Jan 7 15:04 tmp_FILE2015_123_1_3123.LOG
-rw-r--r-- 1 root root 0 Jan 7 15:04 tmp_FILE2015_133_1_3123.LOG
-rw-r--r-- 1 root root 0 Jan 7 16:04 tmp_FILE2015_133_1_3125.LOG
-rw-r--r-- 1 root root 0 Jan 7 16:04 tmp_FILE2015_133_1__3223125.LOG
-rw-r--r-- 1 root root 0 Jan 7 16:04 tmp_FILE2015_133_1_3223125.LOG
I need to remove tmp_ and I can do like this:
for i in *; do s=$(sed -r 's/^(tmp_)(.*.LOG)/\2/' <<< $i); if [[ "$i" != "$s" ]]; then mv "$i" "$s"; fi; done;
But I need to do this for just older than 1 hour (modified time) files:
For example ( now: Jan 7 16:10 ):
-rw-r--r-- 1 root root 0 Jan 7 13:00 FILE2015_123_1_3123.LOG
-rw-r--r-- 1 root root 0 Jan 7 15:04 FILE2015_133_1_3123.LOG
-rw-r--r-- 1 root root 0 Jan 7 15:01 FILE2015_133_1_3125.LOG
-rw-r--r-- 1 root root 0 Jan 7 16:04 tmp_FILE2015_133_1__3223125.LOG
-rw-r--r-- 1 root root 0 Jan 7 16:10 tmp_FILE2015_133_1_3223125.LOG
How can I do that?
This will operate on all files modified in the last hour:
for orig_file in $(find . -type f -depth 1 -mtime -60m); do
new_file="${orig_file#./tmp_}"
if [[ "$new_file" != "$orig_file" ]]; then
mv "$orig_file" "$new_file";
fi;
done
If you want to operate on files older than one hour use +60m instead
I've changed the use of sed to use some built in bash functionality.
I know how to delete the files the files which are more than 60 days old. But I have to satisfy below conditions. Please help me to get correct script to automate this.
I have below files for each day on monthly basis. So I have these files for last 3 years.
vtm_data_12month_20140301.txt
vtm_data_12month_20140301.control
vtm_mtd_20130622.txt
vtm_mtd_20130622.control
vtm_ytd_20131031.txtvtm_ytd_20131031.control
I'd like to write a script find the all files which are more than 60 days old and delete them all but except last month file.
Suppose for january I want to keep the last file (latest) vtm_data_12month_20140131.txt and delete all 30 files. Issue here is, there is chance that I might have files received for January 30th, so in that case I should not delete the latest file, but I have to delete the rest.
Please advice me how can we achieve this via shell script. Your response is highly appreciated.
There are many ways to do this. The two primary approaches are either to (1) use the actual file date to determine whether the files are removed or (2) use the date embedded in the filename to determine the file date. Both have advantages and pitfalls. What you seem to be asking is to remove files 60 days older than the latest date embedded in the filename or 2.
As you have indicated, you may have a number of files with dates mixed relatively close to the end and you may need to adjust the date. Rather than just having the script parse for a maximum file date string contained in the file, you can prompt for the end date to measure 60 days back from. Otherwise, just scan each embedded date and find the max, and subtract 60 days from there. The following script prompts for an end_date.
In fact, the following script contains code to remove files by both methods (and sample data). The code to remove based on the actual file create date ( (1) above ) is commented out below the code that uses the embedded date. Look over the script and understand what it does. It is fairly well commented. NOTE the actual rm command is commented out to prevent accidents (even though it requires you to enter YES to confirm removal). Uncomment the rm line to be able to actually remove files. Drop a comment if you have questions:
#!/bin/bash
oifs="$IFS" # save current IFS (internal field separator) (default ' \t\n')
IFS=$'\n' # set IFS to only break on space
## prompt for path containing files & read
printf "\n enter the path to files to remove (no ending '/'): "
read -r rmpath
## validate directory
[ -d "$rmpath" ] || { printf "\nerror: bad path '%s'\n\n" "$rmpath"; exit 1; }
## prompt for ending date of files to keep
printf "\n enter the _end_ date of files to keep 'yyyymmdd' : "
read -r enddatestr
IFS="$oifs" # reset IFS to original
enddt=$(date -d "$enddatestr" +%s) # get enddt in seconds since epoch
enddt=$((enddt - (60 * 24 * 3600))) # subtract 60 days
declare -a rmarray
## Using embedded filename date
mdate=$(date -d "#$enddt" +%Y%m%d) # get mdate string to compare to filename
## fill rmarray with file dates older than mdate
for i in $(find "$rmpath" -maxdepth 1 -type f); do
ffname="${i##*/}" # full filename component
fname=${ffname%.*} # filename w/o extension
fdate="${fname##*_}" # get file date string
## if fdate before mdate, add to remove array
[ "$mdate" -gt "$fdate" ] && rmarray+=( "$i" )
done
# ### Using actual file creation date
# tgtfile=/tmp/tgt_$(date +%s) # tmp filename to measure against
#
# ## create temp file to measure against with find & set trap to remove
# touch -t $(date -d "#${enddt}" +%Y%m%d%H%M.%S) "$tgtfile" &&
# trap 'rm -rf "$tgtfile"' 0
#
# ## fill array with filenames to remove
# rmarray=( $(find "$rmpath" -maxdepth 1 -type f ! -newer $tgtfile) )
## verify files are contained in rmarray
[ "${#rmarray[#]}" -lt 1 ] && {
printf "\n No files matched the dates for removal.\n\n"
exit 1
}
## print files that will be removed
printf "\n ** the following files will be removed **\n\n"
for i in "${rmarray[#]}"; do
ls -al "$i"
done
## prompt for actual removal
printf "\n Continue with ACTUAL removal (YES to remove) : "
read ans
if [ "$ans" = "YES" ]; then
for i in "${rmarray[#]}"; do
# rm "$i" # NOTE: 'rm' is commented, uncomment to really delete
done
else
printf "\n You entered '%s' (not YES), no removal performed.\n\n" "$ans"
fi
exit 0
test directory:
$ls -l dat/fstst
total 0
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_mtd_20130622.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_mtd_20130622.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_ytd_20131031.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_ytd_20131031.txt
use:
$ bash rmfiles_60days.sh
enter the path to files to remove (no ending '/'): dat/fstst
enter the _end_ date of files to keep 'yyyymmdd' : 20140301
** the following files will be removed **
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_mtd_20130622.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_ytd_20131031.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_ytd_20131031.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_mtd_20130622.control
Continue with ACTUAL removal (YES to remove) : YES
result:
$ ls -l dat/fstst
total 0
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.txt
The following is an example using the actual file date:
test directory:
$ls -l dat/tst
total 324
-rw-r--r-- 1 david david 74 Sep 9 01:23 1.txt
-rw-r--r-- 1 david david 74 Sep 9 01:23 2.txt
-rw-r--r-- 1 david david 201 Aug 1 03:47 3line.dat
-rw-r--r-- 1 david david 205 Aug 1 03:35 3line.dat.sav
-rw-r--r-- 1 david david 88 Aug 13 04:05 catfile.txt
-rw-r--r-- 1 david david 39 Jul 4 14:40 comma
-rw-r--r-- 1 david david 291 Sep 23 03:00 createfile.txt
-rw-r--r-- 1 david david 11 Jul 17 03:54 data.dat
-rw-r--r-- 1 david david 8 Jul 17 03:54 datb.dat
-rw-r--r-- 1 david david 369 Oct 2 14:25 dia.txt
-rw-r--r-- 1 david david 36 Nov 6 15:51 dicta.dat
-rw-r--r-- 1 david david 23895 Sep 9 17:14 dna.dat
-rw-r--r-- 1 david david 243 Nov 4 23:07 domain.dat
-rw-r--r-- 1 david david 276 Nov 23 00:32 ecread.dat
(snip)
use:
$ bash rmfiles_60days.sh
enter the path to files to remove (no ending '/'): dat/tst
enter the _end_ date of files to keep 'yyyymmdd' : 20141031
** the following files will be removed **
-rw-r--r-- 1 david david 205 Aug 1 03:35 dat/tst/3line.dat.sav
-rw-r--r-- 1 david david 29 Jun 29 02:23 dat/tst/f1f2.dat
-rw-r--r-- 1 david david 8 Jul 17 03:54 dat/tst/datb.dat
-rw-r--r-- 1 david david 60 Jul 27 23:24 dat/tst/vowels.txt
-rw-r--r-- 1 david david 134 Aug 11 00:32 dat/tst/outfile.txt
-rw-r--r-- 1 david david 4622 Jun 26 02:49 dat/tst/single.xml
-rw-r--r-- 1 david david 99 Jul 4 14:51 dat/tst/hostnm
-rw-r--r-- 1 david david 115 Aug 7 01:35 dat/tst/ltags.txt
-rw-r--r-- 1 david david 122 Aug 29 11:11 dat/tst/hh.dat
-rw-r--r-- 1 david david 509 Jul 21 17:28 dat/tst/orders.txt
-rw-r--r-- 1 david david 205 Jun 27 01:06 dat/tst/table.html
(snip)
Continue with ACTUAL removal (YES to remove) : YES
result:
$ ls -l dat/tst
total 168
-rw-r--r-- 1 david david 74 Sep 9 01:23 1.txt
-rw-r--r-- 1 david david 74 Sep 9 01:23 2.txt
-rw-r--r-- 1 david david 291 Sep 23 03:00 createfile.txt
-rw-r--r-- 1 david david 369 Oct 2 14:25 dia.txt
-rw-r--r-- 1 david david 36 Nov 6 15:51 dicta.dat
-rw-r--r-- 1 david david 23895 Sep 9 17:14 dna.dat
-rw-r--r-- 1 david david 243 Nov 4 23:07 domain.dat
-rw-r--r-- 1 david david 276 Nov 23 00:32 ecread.dat
-rw-r--r-- 1 david david 93 Nov 2 21:43 empdata.dat
(snip)