What is the difference between find with grep? - unix

What is the difference between these command:
find . –type f –name '*txt*'
and
find . –type f | grep 'txt'
I tried to run this and there is a difference but I want to know why?

The Major difference is FIND is for searching files and directories using filters while GREP is for searching a pattern inside a file or searching process(es)
FIND is an command for searching file(s) and folder(s) using filters such as size , access time , modification time.
The find command lists all of the files within a directory and its sub-directories that match a set of filters. This command is most commonly used to find all of the files that have a certain name.
To find all of the files named theFile.txt in your current directory and all of its sub-directories, enter:
find . -name theFile.txt -print
To look in your current directory and its sub-directories for all of the files that end in the extension .txt , enter:
find . -name "*.txt" -print
GREP :(Globally search a Regular Expression and Print)
Searches files for a specified string or expression.
Grep searches for lines containing a specified pattern and, by default, writes them to the standard output.
grep myText theFile.txt
Result : Grep will print out each line contain the word myText.

In your first example, you are using the find utility to list the filenames of regular files where the filename includes the string txt.
In your second example, you are using the find utility to list the filenames of regular files and feeding the resultant filenames via a pipe to the grep utility which searches the contents of the pipe (a list of filenames, one per line) for the string txt. Each time this string is found, the corresponding line (which is a filename) is outputted.

When you have a path with txt in the directory name, the second command will find a match. When you do not want to match paths like txtfiles/allfiles.tgz and transactions/txtelevisions/bigscreen.jpg you will want to use the first.

The difference between the two is that in the first case, find is looking for files whose name (just name) matches the pattern.
In the second case, find is looking for all files of type 'f' and outputting their relative paths as strings. That result gets piped to grep, which filters the input strings to those matching the pattern. The pattern 'txt' will filter the filepath results for the pattern. Importantly, the second case will include filepaths that match anywhere in the path, not just in the filename. The first case will not do that.

The first command will display files having txt in their name.
Whereas the second command will highlight the lines of all the files having txt in their content.

Related

Getting the filename from a directory only using a string from the filename? and setting that found filename equal to a variable? unix

Could someone steer me towards a resource to do the following in unix: I want to set a variable equal to a filename so that I can input that variable/filename into a command line tool. I am trying to automate the process of running this command line tool by doing so.
My input files will always have the same string at the end their unique names.
How can I get this filename by searching the directory for a string AND successfully input that variable into command line tool?
so the unix code would look something like:
file1="find . -maxdepth 1 -name "string""
my command line tool --input $file1
thanks for your patience!
P.S only one file with that string will be in a directory at a time.
Instead of work with variables you can directly use the output of find command as parameter in your command line:
my_command_line_tool --input "$(find . -maxdepth 1 -name "*string*")"
If you expect more than one file you may remove the outer quotation marks. But this may broke the command if you have files which match the string, but have special characters like space, new line, etc in filename.

Glob path to get newest file only

Let's say I have a directory with product inventories that are saved per day:
$ ls *.csv
2014_01_01.csv
2014_01_02.csv
...
Is there a glob pattern that will only grab the newest file? Or do I need to chain it with other commands? Basically I'm just looking to do what would about to a LIMIT 1 based on the filename sort.
Assuming your shell is bash, ksh93 or zsh, and your files have the same naming convention as the example in your question:
files=( *.csv )
printf "The newest file is %s\n" "${files[-1]}"
Since the date in the filenames is in a format that naturally sorts, storing all of them in an array and taking the last element gives you the newest one (And conversely the first element is the oldest one).

how to list all files in a directory which contain only one dot

I am trying to get all files in a directory which contain only one extension dot such as abcd.py and not abcd.efg.py
i've tried ls ~/scripts/[^.].py with no success
eventually, I used: find ~/scripts/ -regex "[^.]*.py"

How to search for a pattern in a file from the end of a directory using grep?

I need to search for files containing a pattern in a directory (to search from the end of the directory to the start).
This is the command I use now,
grep -rl 'pattern'
Is there any command to search for a pattern from the last file of a directory to the first file?
If you want to grep to search in some order, you need to pass it a list of file names in the order you want. If you want the files in the current directory in reverse order of name, ls -r would do the job. How about something like this?
ls -1br | xargs grep 'pattern'
Note the -b, which is needed to mitigate problems with spaces and metacharacters in file names.
Note also that this won't cope well with sub-directories. But the principle is sound - generate a list of files in the order you want and pass it to grep using xargs.

why is zsh globbing not working with find command?

I have been using zsh globbing for commands such as:
vim **/filename
vim *.html.erb
and so on, but when I type in something like:
find . -name *mobile*
I get the response:
zsh: no matches found: *mobile*
Why?
find . -name *mobile* # does not work
vs
find . -name '*mobile*' # works
The difference is due to the steps that the shell takes when it parses a line. Normally, the shell expands any wildcards it finds before it runs the command. However, the single quotes mark the argument as being a literal, which means that the shell does not perform wildcard expansion on that argument before running the command.
To demonstrate the difference, suppose you are in a directory with the following files:
$ tree
./
mobile.1
dir/
mobile.2
In the first case, without single quotes, zsh will process as follows:
expand the glob, rendering simply mobile.1 (because that is the only matching filename in the current directory
pass the result to find, hence:
find . -name mobile.1
So find will only look for files named literally mobile.1
In the second form, with single quotes, the entire glob will be preserved and passed to find:
find . -name *mobile*
Which means that find will look for any filename containing the string "mobile".
The important thing to note here is that both zsh and find support the same wildcard syntax; by using single quotes, you induce find to handle the wildcards in this case rather than zsh.
Turns out that all you have to do to solve the problem is add some quotes around the input:
find . -name '*mobile*'
I don't really have an answer as to why just yet...and the documentation doesn't have an something that sticks out to me, but let me know if you know the answer!
For archival purposes, here is my substantial edit/reformatting of #Swiss's response above. The edit queue has been full every time I tried to edit, for hours, so I want to preserve this for future reference. I hope it's deemed to be constructive.
To be super-clear it's a revision of another person's work.
find . -name *mobile* # does not work
vs
find . -name '*mobile*' # works
The difference is due to the steps that the shell takes when it parses a line. Normally, the shell expands any wildcards it finds before it runs the command. However, single quotes marks the argument as being a literal, which means that the shell does not preform wildcard expansion on that argument before running the command.
To demonstrate the difference, suppose you are in a directory with the following files:
$ tree
./
mobile.1
dir/
mobile.2
In the first case, without single quotes, zsh will process as follows:
expand the glob, rendering simply mobile.1 (because that is the only matching filename in the current directory
pass the result to find, hence:
find . -name mobile.1
So find will only look for files named literally mobile.1
In the second form, with single quotes, the entire glob will be preserved and passed to find:
find . -name *mobile*
Which means that find will look for any filename containing the string "mobile".
The important thing to note here is that both zsh and find support the same wildcard syntax; by using single quotes, you induce find to handle the wildcards in this case rather than zsh.

Resources