How to use find ,-exec and cp commands together in ruby code? - ruby-on-rails

I would like to find .plist files recursively in a folder and copy that files into new folder by a single terminal command.
find /Users/admin/Desktop/Norton/StaticAnalysis -iname "*.plist" -exec cp {} /Users/admin/Desktop/Test \;
This is the command which is working fine in terminal.
But i have to use this command in ruby code.
when i use this in ruby code like
CODE 1:
system ("find /Users/admin/Desktop/Norton/StaticAnalysis -iname \"*.plist\" -exec cp {} /Users/admin/Desktop/Test \;")
puts $?.success?
OUTPUT IS:
find: -exec: no terminating ";" or "+"
false
CODE 2:
system ("find /Users/admin/Desktop/Norton/StaticAnalysis -iname \"*.plist\" -exec cp {} /Users/admin/Desktop/Test \;");
end
puts $?.success?
OUTPUT IS:
siva.rb:2: syntax error, unexpected keyword_end, expecting end-of-input
So please help me how to use this in ruby code.

Have you tried with FileUtils module (fileutils.rb)?
It has namespace for several file utility methods for copying, moving, removing, etc.

system ("find ... -exec ... \;")
ruby is interpreting the \; within double quotes as just ;. You need to double the backslash
system ("find ... -iname \"*.plist\" -exec ... \\;")
Or use different outer quotes, which means you don't have to escape the inner quotes
system %q{find ... -iname "*.plist" -exec ... \;}

Related

How to show the full path for a file found using the find command and given to grep to match a string

I have a lot of config.php files in subdirectories below where I invoke the find command and I want to list the path names of only those for which a grep string match is found. Here is what I've tried so far.
find `pwd -P` -name config.php -print -exec grep 'assetBasePath.*cloudfront' {} \;
It partially does the job because find does list the paths for all the config.php files it found, and grep prints the matching line in the file if the pattern does indeed match one.
What I want to achieve is an output similar to the above, but where only the pathnames for the files that have a grep match are shown.
Move the -print to the right-hand end so it is "gated" by the outcome of exec:
find `pwd -P` -name config.php -exec grep 'assetBasePath.*cloudfront' {} \; -print

grep without extended pattern option on finding files that have characters after the pattern

I have set of files in a directory. In those, few files contain a matching pattern config_dict["backup.moduleDir"] and some characters following them. In few other files the pattern appears exactly at the end of the line (no characters followed after the pattern). Note that, the pattern appears exactly one time in all these files.
Now, I want to find those file names which have some characters following a matching pattern. I use the below code:
find . -type f -name "*.py" -exec grep -El 'config_dict\["backup.moduleDir"].+$' {} \;
Actually I want to avoid the use of regex character '+' and extended pattern option -E of grep. So I tried using the grep -v logic by the following 2 ways, but it did not give me the expected result. What really went wrong in the below 2 methods?
grep -vl 'config_dict\["backup.moduleDir"\]$' `find . -type f -name "*.py" -exec grep -l 'backup.moduleDir' {} \;`
find . -type f -name "*.py" -exec grep -l 'backup.moduleDir' {} \; | xargs grep -vl 'config_dict["backup.moduleDir"]$'
Surprisingly in the above working code, I have to escape only the opening square bracket '[' where as escaping is optional for closing square bracket ']' and for double quotes and for dot character between the strings "backup" and "moduleDir". How this is possible?
Using a simple dot without + does the job:
grep 'config_dict\["backup.moduleDir"].' *.py
This will find config_dict["backup.moduleDir"] followed by at least 1 character, in all python scripts.

what does `{}` mean as a file name in output from egrep?

I am on ubuntu debian 12.04, and I ran a find command to add something to all of my python files:
find . iname "*.py" -exec echo "import os" >> {} \;
The command runs without error and I want to validate the results so I egrep all of the files:
egrep -in "import os" *
And I get results looking like this:
{}:35:import os
{}:36:import os
{}:37:import os
{}:38:import os
{}:39:import os
...and the numbers go until 51 for some reason. What does this mean?
Thank you.
Your first command:
find . iname "*.py" -exec echo "import os" >> {} \;
Is looking for files ending in .py, and for each one is putting the string "import os" in a file called {}. Presumably there are 51 matches.
So egrep, when you run it, the * matches all files, including your file called {}. With {}:35:import os it's telling you that "in the file {}, at line 35, there's the string you're looking for"
This command:
find . iname "*.py" -exec echo "import os" >> {} \;
...creates a file named {} (in bash, and other shells which honor redirections in positions other than head and tail -- this is an extension which the POSIX sh standard does not require). It does not modify the files found by find. (This is because the >> is acting as a command to the shell that's starting find; it's not modifying the behavior of -exec -- and even if it did, -exec directly uses execve() to invoke the command given; it doesn't start that command through a shell, so it doesn't honor shell constructs such as redirections, so you'd be passing literal >> as an argument to echo on any shells not implementing this extension, still not performing a redirection on the individual files found).
Now, if you did want to modify the files found by find, you might do so like this:
find . -iname '*.py' -exec sh -c 'for f; do echo "import os" >>"$f"; done' {} +
Noteworthy differences:
The redirection is invoked inside a shell started with exec sh; thus, there's a shell present to honor it after the individual filenames have been resolved.
-exec ... {} + is used, which is much more efficient than -exec ... {} ; (the former runs as few subcommands as possible; the latter runs one per file found).
{} is a placeholder that is replaced by find with the filename that matches the given condition, in this case {} is replaced with filename that match the pattern "*.py".
However your find command isn't actually doing that, as the >> {} is not actually part of the -exec block, but interpreted by the shell as a redirect for the whole find command, so the {} never gets replaced by find with the proper filename and instead you are redirecting into a file called {}. To make things more clear, the command you are actually executing is this:
find . iname "*.py" -exec echo "import os" \; >> {}
Meaning for every *.py file you add a line containing "import os" into a file called {}. The output of grep is just filename:linenumber:matched_line so you get a {} in there as that is the filename.
If you are wondering how the \; survives and why you are not getting a:
find: missing argument to `-exec'
The shell doesn't actually care where in the command line the redirect occurs:
echo 1 2 3 4 5 6 7 > foo
is the same as:
echo 1 2 > foo 3 4 5 6 7
and gives you this each time:
$ cat foo
1 2 3 4 5 6 7
Also worth to mention >> is an append operator, so even if you fix your command you are adding to the end of the Python files, while import os probably should go to the top of the file.

How to use grep to search only in a specific file types?

I have a lot of files and I want to find where is MYVAR.
I'm sure it's in one of .yml files but I can't find in the grep manual how to specify the filetype.
grep -rn --include=*.yml "MYVAR" your_directory
please note that grep is case sensitive by default (pass -i to tell to ignore case), and accepts Regular Expressions as well as strings.
You don't give grep a filetype, just a list of files. Your shell can expand a pattern to give grep the correct list of files, though:
$ grep MYVAR *.yml
If your .yml files aren't all in one directory, it may be easier to up the ante and use find:
$ find -name '*.yml' -exec grep MYVAR {} \+
This will find, from the current directory and recursively deeper, any files ending with .yml. It then substitutes that list of files into the pair of braces {}. The trailing \+ is just a special find delimiter to say the -exec switch has finished. The result is matching a list of files and handing them to grep.
If all your .yml files are in one directory, then cd to that directory, and then ...
grep MYWAR *.yml
If all your .yml files are in multiple directories, then cd to the top of those directories, and then ...
grep MYWAR `find . -name \*.yml`
If you don't know the top of those directories where your .yml files are located and want to search the whole system ...
grep MYWAR `find / -name \*.yml`
The last option may require root privileges to read through all directories.
The ` character above is the one that is located along with the ~ key on the keyboard.
find . -name \*.yml -exec grep -Hn MYVAR {} \;

How can I grep hidden files?

I am searching through a Git repository and would like to include the .git folder.
grep does not include this folder if I run
grep -r search *
What would be a grep command to include this folder?
Please refer to the solution at the end of this post as a better alternative to what you're doing.
You can explicitly include hidden files (a directory is also a file).
grep -r search * .[^.]*
The * will match all files except hidden ones and .[^.]* will match only hidden files without ... However this will fail if there are either no non-hidden files or no hidden files in a given directory. You could of course explicitly add .git instead of .*.
However, if you simply want to search in a given directory, do it like this:
grep -r search .
The . will match the current path, which will include both non-hidden and hidden files.
I just ran into this problem, and based on #bitmask's answer, here is my simple modification to avoid the problem pointed out by #sehe:
grep -r search_string * .[^.]*
Perhaps you will prefer to combine "grep" with the "find" command for a complete solution like:
find . -exec grep -Hn search {} \;
This command will search inside hidden files or directories for string "search" and list any files with a coincidence with this output format:
File path:Line number:line with coincidence
./foo/bar:42:search line
./foo/.bar:42:search line
./.foo/bar:42:search line
./.foo/.bar:42:search line
To prevent matching . and .. which are not hidden files, you can use grep with ls -A like in this example:
ls -A | grep "^\."
^\. states that the first character must be .
The -A or --almost-all option excludes the results . and .. so that only hidden files and directories are matched.
You may want to use this approach, assuming you're searching the current directory (otherwise replace . with the desired directory):
find . -type f | xargs grep search
or if you just want to search at the top level (which is quicker to test if you're trying these out):
find . -type f -maxdepth 1 | xargs grep search
UPDATE: I modified the examples in response to Scott's comments. I also added "-type f".
To search within ONLY all hidden files and directories from your current location:
find . -name ".*" -exec grep -rs search {} \;
ONLY all hidden files:
find . -name ".*" -type f -exec grep -s search {} \;
ONLY all hidden directories:
find . -name ".*" -type d -exec grep -rs search {} \;
All the other answers are better. This one might be easy to remember:
find . -type f | xargs grep search
It finds only files (including hidden) and greps each file.
To find only within a certain folder you can use:
ls -al | grep " \."
It is a very simple command to list and pipe to grep.
In addition to Tyler's suggestion, Here is the command to grep all files and folders recursively including hidden files
find . -name "*.*" -exec grep -li 'search' {} \;
You can also search for specific types of hidden files like so for hidden directory files:
grep -r --include=*.directory "search-string"
This may work better than some of the other options. The other options that worked can be too slow.

Resources