I'm trying to run hunspell over my source tree. However when I run this:
find . -name *.html | xargs hunspell -H
The Hunspell editor comes up on the screen, but it won't accept any typed input - all of the input appears at the next command prompt when I type Ctrl+C to exit the hunspell editor. Is there a way I can pipe files to hunspell?
Thanks,
Kevin
This is based on an answer by nosid here.
xargs -a <(find . -name *.html) hunspell -H
see nosid's answer for an explanation (:
Related
I am trying to find a line of code in a folder and using the terminal. I use this command, which I think should work:
MacBook-Pro:myWordpress myId$ grep "<?php get_template_part('loop', 'archives'); ?>" -R
where the folder I am inspecting is called "myWordpress". But I get this:
grep: warning: recursive search of stdin
I don't use much the terminal, so I am unsure as to how to do what I want. Any help appreciated. Thanks
David
You have to specify the directory too as the last argument:
grep -r -F "string to search" /path/to/dir
Or if you want to search in current directory, write . as the target directory:
grep -r -F "string to search" .
If you don't specify a directory, grep will try to search in the standard input, but recursive search does not make sense there - that's why you get that warning.
The manpage for grep says that:
Not all grep implementations support -r and among those that do, the behaviour with symlinks may differ.
In this case, you can try a different approach, with find and xargs:
find /path/to/dir -name '*.*' -print0 | xargs -0r grep -F "string to search"
Again, you can write . as the directory parameter (after find) if you want to search in the current directory.
Edit: as #EdMorton pointed out, the -F option is needed for grep if you want to search for a simple text instead of a regular expression. I added it to my examples above as it seems you are trying to search for PHP snippets that may contain special characters, which would lead to a different output in regexp mode.
For macOS this will be super useful and easy, and also it highlights the search result matches of text!
brew install ack
ack "text"
I would suggest giving a try to ripgrep
$ brew install ripgrep
Besides been faster it gives you multiple options, check the examples
Once you have it installed just need to do:
$ rg your-string
Never use -r or -R with grep. It is a terrible idea, completely unnecessary (the UNIX tool to find files is named find!), and makes your code GNU-specific.
Best I can tell without any sample input/output, all you need is:
grep "<?php get_template_part('loop', 'archives'); ?>" *
or if you have files AND directories in your current directory but only want to search in the files:
find . -type f -maxdepth 1 -exec grep -H "<?php get_template_part('loop', 'archives'); ?>" {} +
or to search in all sub-directories:
find . -type f -exec grep -H "<?php get_template_part('loop', 'archives'); ?>" {} +
If that doesn't do what you want then provide the sample input/output in your question.
Say I want to edit every .html file in a directory one after the other using vim, I can do this with:
find . -name "*.html" -exec vim {} \;
But what if I only want to edit every html file containing a certain string one after the other? I use grep to find files containing those strings, but how can I pipe each one to vim similar to the find command. Perphaps I should use something other than grep, or somehow pipe the find command to grep and then exec vim. Does anyone know how to edit files containing a certain string one after the other, in the same fashion the find command example I give above would?
grep -l 'certain string' *.html | xargs vim
This assumes you don't have eccentric file names with spaces etc in them. If you have to deal with eccentric file names, check whether your grep has a -z option to terminate output lines with null bytes (and xargs has a -0 option to read such inputs), and if so, then:
grep -zl 'certain string' *.html | xargs -0 vim
If you need to search subdirectories, maybe your version of Bash has support for **:
grep -zl 'certain string' **/*.html | xargs -0 vim
Note: these commands run vim on batches of files. If you must run it once per file, then you need to use -n 1 as extra options to xargs before you mention vim. If you have GNU xargs, you can use -r to prevent it running vim when there are no file names in its input (none of the files scanned by grep contain the 'certain string').
The variations can be continued as you invent new ways to confuse things.
With find :
find . -type f -name '*.html' -exec bash -c 'grep -q "yourtext" "${1}" && vim "${1}"' _ {} \;
On each files, calls bash commands that grep the file with yourtext and open it with vim if text is matching.
Solution with a for cycle:
for i in $(find . -type f -name '*.html'); do vim $i; done
This should open all files in a separate vim session once you close the previous.
I am trying the following to use a vim to open every txt file under current directory.
find . -name "*.txt" -print | while read aline; do
read -p "start spellchecking fine: $aline" sth
vim $aline
done
Running it in bash complains with
Vim: Warning: Input is not from a terminal
Vim: Error reading input, exiting...
Vim: Finished.
Can anyone explain what could possibly goes wrong? Also, I intend to use read -p for prompt before using vim, without no success.
Try:
vim $( find . -name "*.txt" )
To fix your solution, you can (probably) do:
find . -name "*.txt" -print | while read aline; do
read -p "start spellchecking fine: $aline" sth < /dev/tty
vim $aline < /dev/tty
done
The problem is that the entire while loop is taking its input from find, and vim inherits that pipe as its stdin. This is one technique for getting vim's input to come from your terminal. (Not all systems support /dev/tty, though.)
With shopt -s globstar you can purge out find and thus make bash not execute vim in a subshell that receives output from find:
shopt -s globstar
shopt -s failglob
for file in **/*.txt ; do
read -p "Start spellchecking fine: $file" sth
vim "$file"
done
. Another idea is using
for file in $(find . -name "*.txt") ; do
(in case there are no filenames with spaces or newlines.)
Often the simplest solution is the best, and I believe this is it:
vim -o `find . -name \*.txt -type f`
The -type f is to ensure only files ending .txt are opened as you don't discount the possibility that there may be subdirectories that have names that end in ".txt".
This will open each file in a seperate window/bufer in vim, if you don't require this and are happy with using :next and :prefix to navigate through the files, remove "-o" from the suggested comand-line above.
The proper way to open all files in one single vim instance is (provided the number of files doesn't exceed the maximal number of arguments):
find . -name '*.txt' -type f -exec vim {} +
Another possibility that fully answers the OP, but with the benefit that it is safe regarding file names containing spaces or funny symbols.
find . -name '*.txt' -type f -exec bash -c 'read -p "start spellchecking $0"; vim "$0"' {} \;
I just need to search for a specific directory that can be anywhere is there a way to run this command until the first match? Thanx!
Im now ussing
find / -noleaf -name 'experiment' -type d | wc -l
As Rudolf Mühlbauer mentions, the -quit option tells find to quit. The man page example is that
find /tmp/foo /tmp/bar -print -quit
will print only /tmp/foo.
Slightly more generally, find may be the wrong tool for what you want to do. See man locate. For example, on my system,
locate experiment | head -3
produces
/usr/lib/tc/experimental.dist
/usr/share/doc/xorg/reference/experimental.html
/usr/share/doc/xorg/reference/experimental.txt
while locate -r 'experimental..$' produces (with 6 lines snipped for brevity)
/usr/src/linux-headers-3.2.0-24-generic/include/config/experimental.h
(snip)
/usr/src/linux-headers-3.2.0-32-generic/include/config/experimental.h
I'm trying to use find in Windows 7 with GNU sed to recursively replace a line of text in multiple files, across multiple directories. I looked at this question but the PowerShell solution seems to work with only one file, and I want to work with all files with a certain extension, recursively from the current directory. I tried this command:
find "*.mako" -exec sed -i "s:<%inherit file="layout.mako"/>:<%inherit file="../layout.mako"/>:"
But that gives me a bunch of crap and doesn't change any files:
---------- EDIT.MAKO
File not found - -EXEC
File not found - SED
File not found - -I
File not found - LAYOUT.MAKO/>:<%INHERIT FILE=../LAYOUT.MAKO/>:
How can I do this? It seems like I should have all the tools installed that I need, without having to install Cygwin or UnixUtils or anything else.
Edit: okay, working with GNU find, I still can't get anywhere, because I can't get the find part to work:
> gfind -iname "*.mako" .
C:\Program Files (x86)\GnuWin32\bin\gfind.exe: paths must precede expression
> gfind . -iname "*.mako"
C:\Program Files (x86)\GnuWin32\bin\gfind.exe: paths must precede expression
> gfind -iname "*.mako" .
C:\Program Files (x86)\GnuWin32\bin\gfind.exe: paths must precede expression
I was originally not using GNU find in Windows 7 because of this question.
Edit:
I tried the following, but sed doesn't see any input files this way:
> ls -r | grep mako | sed -i 's/file="layout.mako"/file="..\/layout.mako"/'
sed.exe: no input files
FIND from windows is being found instead of find from gnu.
So, rename your find.exe (from gnu) to gfind.exe (for example) and then call gfind instead of find when you wish to run it.
[edit]
gfind . -name "*.mako" (not gfind -iname "*.make" .)
[/edit]
You're executing the regular windows 'find' command, which has completely different command line arguments than gnu find. MS find has no capability of executing a program for each match, it simply searches.
Addition to Marc B/KevinDTimm answers: your find syntax is wrong.
It is not:
find "*.mako"
but:
find -name "*.mako"
Also, if there are directories that matches "*.mako", they would be sent to sed. To avoid that:
find -name "*.mako" -type f
Finally, I think that you are missing a '\;' at the end or your find command.
In Powershell, note the escape sequence using backticks
find . -type f -exec grep hello `{`} `;
Its much easier to use xargs
find . | xargs grep hello
I tried the following, but sed doesn't see any input files this way:
ls -r | grep mako | sed -i 's/file="layout.mako"/file="../layout.mako"/'
sed.exe: no input files
With this you are now running into PowerShell's "ls" alias. Either call "ls.exe" or go all PowerShell like this:
ls -r | select-string mako -list | select -exp path | sed -i 's/file="layout.mako"/file="..\/layout.mako"/'
Edit:
Workaround if stdin handling doesn't seem to be working.
ls -r | select-string mako -list | select -exp path | % {sed -i 's/file="layout.mako"/file="..\/layout.mako"/' $_}
Per your
Edit:
I tried the following, but sed doesn't see any input files this way:
ls -r | grep mako | sed -i
's/file="layout.mako"/file="../layout.mako"/' sed.exe: no input files
you need to use xargs to assemble the list of files passed to sed, i.e.
ls -r | grep mako | xargs sed -i
's\:file="layout.mako":file="../layout.mako":'
Note that for most versions of sed, you can use an alternate character to identify the substitute match/replace strings (usually '/'). Some seds require escaping that alternate char, which I have done in this example.
I hope this helps.