Using find and xargs to list the timestamp of a file which has found from a containing string - linux

I have to find a file from a given string inside and list this files timestamp only using find and xargs commands in linux command terminal
I've tried this code and it worked out but it gives error on ls command for long lines, need more smooth answer for this particular problem
find /home/stajyer -type f -exec grep -H 'ayberk' {} \; |xargs ls -l
Result:
ls: cannot access '/home/stajyer/myNameChangedFile/aFileInChangedFile4:ayberk': No such file or directory
ls: cannot access 'Binary': No such file or directory
ls: cannot access 'file': No such file or directory
ls: cannot access 'matches': No such file or directory
-rw------- 1 stajyer stajyer 9787 Haz 25 09:45 /home/stajyer/.bash_history
how can my code give less error corresponding to ls command?

From man xargs:
xargs reads
items from the standard input, delimited by blanks (which can be
protected with double or single quotes or a backslash) or newlines,
To disable that you can go with a zero delimetered stream and use -0 or --null option with xargs and -print0 with find. It would look like this:
find /home/stajyer -type f -exec grep -qH 'ayberk' {} \; -print0 | xargs -0 ls -l
Tested on repl.

Related

Linux search file with given name containing string recursively

From Linux shell, Let's say I'm in directory /dir and I want to find, recursively in all subfolders, all the files which contain in the name the string name_string and, inside, the string content_string. name_string might be at the beginning, center or end of the file name. How could I do that?
I was trying to sue grep as:
grep -r content_string /dir/*name_string*
But I haven't been lucky so far.
Thanks!
The find command's -exec grep can solve your question, as in this example:
find /dir -name "*name_string*" -exec grep "content_string" {} /dev/null \;
This, however, will not only show you the name of the file, but also the line, containing the content_string. In case you just want the name of the string:
find /dir -name "*name_string*" -exec grep -l "content_string" {} \;
Obviously, you can use -exec with other commands (head, tail, chmod, ...)
You could also use find with xargs
find /dir -name "*name_string*"|xargs -0 -I '{}' grep "content_string" '{}'
With xargs -0, grep is executed only once and its parameter are all files found with the specified pattern:
grep file1 file2 file3 filen
#it will much faster because there is no overhead in fork and exec like this:
grep file1
grep file2
grep file3
..

linux bash count size of files in folder

i saw a few posts in forum but i cant manage to make them work for me
i have a script that runs in a folder and i want it to count the size only of the files in that folder but without the folders inside.
so if i have
file1.txt
folder1
file2.txt
it will return the size in bytes of file1+file2 without folder1
find . -maxdepth 1 -type f
gives me a list of all the files i want to count but how can i get the size of all this files?
The tool for this is xargs:
find "$dir" -maxdepth 1 -type f -print0 | xargs -0 wc -c
Note that find -print0 and xargs -0 are GNU extensions, but if you know they are available, they are well worth using in your script - you don't know what characters might be present in the filenames in the target directory.
You will need to post-process the output of wc; alternatively, use cat to give it a single input stream, like this:
find "$dir" -maxdepth 1 -type f -print0 | xargs -0 cat | wc -c
That gives you a single number you can use in following commands.
(I've assumed you meant "size" in bytes; obviously substitute wc -m if you meant characters or wc -l if you meant lines).

How to list the files using sort command but not ls -lrt command

I am writing a shell script to check some parameters like errors or exception inside the log files which are getting generated in last 2 hours inside the directory /var/log. So this is command I am using:
find /var/log -mmin -120|xargs egrep -i "error|exception"
It is displaying the list of file names and its corresponding parameters(errors and exceptions) but the list of files are not as per the time sequence. I mean the output is something like this(the sequence):
/var/log/123.log:RPM returned error
/var/log/361.log:There is error in line 1
/var/log/4w1.log:Error in configuration line
But the sequence how these 3 log files have been generated is different.
/var/log>ls -lrt
Dec24 1:19 361.log
Dec24 2:01 4w1.log
Dec24 2:15 123.log
So I want the output in the same sequence,I mean like this:
/var/log/361.log:There is error in line 1
/var/log/4w1.log:Error in configuration line
/var/log/123.log:RPM returned error
I tried this:
find /var/log -mmin -120|ls -ltr|xargs egrep -i "error|exception"
but it is not working.
Any help on this is really appreciated.
If your filenames don't have any special characters (like newline characters, etc), all you need is another call to xargs:
find . -type f -mmin -120 | xargs ls -tr | xargs egrep -i "error|exception"
Or if your filenames contain said special chars:
find . -type f -mmin -120 -print0 | xargs -0 ls -tr | xargs egrep -i "error|exception"
You can prepend the modified time using the -printf argument to find, then sort, and then remove the modified time with sed:
find /var/log -mmin -120 -printf '%T#:%p\n' | sort -V | sed -r 's/^[^:]+://' | xargs egrep -i "error|exception"
find ... -printf '%T#:%p\n' prints out each found file (%p) prepended by the seconds since the UNIX epoch (%T#; e.g., 1419433217.1835886710) and a colon separator (:), each on a new line (\n).
sort -V sorts the files naturally by modification time because it is at the beginning of each line (e.g., 1419433217.1835886710:path/to/the/file).
sed -r 's/^[^:]+://' takes each line in the format 123456789.1234:path/to/the/file and strips out the modification time leaving just the file path path/to/the/file

CVS Tagging recursively from within a shell script

My team uses CVS for revision control.I need to develop a shell script which extracts the content from a file and does a CVS tag to all .txt files(also the text files present in the sub-directories of the current direcotry) with that content. The file from which the content is extracted ,the script ,both are present in the same directory.
I tried running the script :
#!bin/bash
return_content(){
content=$(cat file1)
echo $content
}
find . -name "*.txt" -type f -print0|grep - v CVS|xargs -0 cvs tag $content
file1=> the file from where the content is extracted
"abc"=> content inside file1
Output:
abc
find: paths must precede expression
Usage: find [path...] [expression]
cvs tag: in directory
cvs [tag aborted]: there is no version here; run 'cvs checkout' first
I cannot figure out the problem. Please help
There are a few problems with the script.
1) The shebang line is missing the root /.
You have #!bin/bash and it should be #!/bin/bash
2) the -v option to grep has a space between the - and the v (and it shouldn't)
3) You don't actually call the return_content function in the last line - you refer to a variable inside the function. Perhaps the last line should look like:
find . -name "*.txt" -type f -print0|grep -v CVS|\
xargs -0 cvs tag $( return_content )
4) even after fixing all that, you may find that the grep complains because the print0 is passing it binary data (there are embedded nulls due to the -print0), and grep is expecting text. You can use more arguments to the find command to perform the function of the grep command and cut grep out, like this:
find . -type d -name CVS -prune -o -type f -name "*.txt" -print0 |\
xargs -0 cvs tag $( return_content )
find will recurse through all the entries in the current directory (and below), discarding anything that is a directory named CVS or below, and of the rest it will choose only files named *.txt.
I tested my version of that line with:
find . -type d -name CVS -prune -o -type f -name "*.txt" -print0 |\
xargs -t -0 echo ls -la
I created a couple of files with spaces in the names and .txt extensions in the directory so the script would show results:
bjb#spidy:~/junk/find$ find . -type d -name CVS -prune -o \
-type f -name "*.txt" -print0 | xargs -t -0 ls -la
ls -la ./one two.txt ./three four.txt
-rw-r--r-- 1 bjb bjb 0 Jun 27 00:44 ./one two.txt
-rw-r--r-- 1 bjb bjb 0 Jun 27 00:45 ./three four.txt
bjb#spidy:~/junk/find$
The -t argument makes xargs show the command it is about to run. I used ls -la instead of cvs tag - it should work similarly for cvs.

List files over a specific size in current directory and all subdirectories

How can I display all files greater than 10k bytes in my current directory and it's subdirectories.
Tried ls -size +10k but that didn't work.
find . -size +10k -exec ls -lh {} \+
the first part of this is identical to #sputnicks answer, and sucesffully finds all files in the directory over 10k (don't confuse k with K), my addition, the second part then executes ls -lh or ls that lists(-l) the files by human readable size(-h). negate the h if you prefer. of course the {} is the file itself, and the \+ is simply an alternative to \;
which in practice \; would repeat or:
ls -l found.file; ls -l found.file.2; ls -l found.file.3
where \+ display it as one statement or:
ls -l found.file found.file.2 found.file.3
more on \; vs + with find
Additionaly, you may want the listing ordered by size. Which is relatively easy to accomplish. I would at the -s option to ls, so ls -ls and then pipe it to sort -n to sort numerically
which would become:
find . -size +10k -exec ls -ls {} \+ | sort -n
or in reverse order add an -r :
find . -size +10k -exec ls -ls {} \+ | sort -nr
finally, your title says find biggest file in directory. You can do that by then piping the code to tail
find . -size +10k -exec ls -ls {} \+ | sort -n | tail -1
would find you the largest file in the directory and its sub directories.
note you could also sort files by size by using -S, and negate the need for sort. but to find the largest file you would need to use head so
find . -size +10k -exec ls -lS {} \+ | head -1
the benefit of doing it with -S and not sort is one, you don't have to type sort -n and two you can also use -h the human readable size option. which is one of my favorite to use, but is not available with older versisions of ls, for example we have an old centOs 4 server at work that doesn't have -h
Try doing this:
find . -size +10k -ls
And if you want to use the binary ls :
find . -size +10k -exec ls -l {} \;
I realize the assignment is likely long over. For anyone else:
You are overcomplicating.
find . -size +10k
I'll add to #matchew answer (not enough karma points to comment):
find . -size +10k -type f -maxdepth 1 -exec ls -lh {} \; > myLogFile.txt
-type f :specify regular file type
-maxdepth 1 :make sure it only find files in the current directory
You may use ls like that:
ls -lR | egrep -v '^d' | awk '$5>10240{print}'
Explanation:
ls -lR # list recursivly
egrep -v '^d' # only print lines which do not start with a 'd'. (files)
only print lines where the fifth column (size) is greater that 10240 bytes:
awk '$5>10240{print}'

Resources