Bash Script - Need find command to output file paths enclosed in double quotes without line breaks - linux

I have been using cscope/ctags database. However after sometime I noticed that some files in my cscope.files that stores the result of my find command, are broken into two or more lines. This causes them being ignored by cscope/ctags while indexing.
Currently I use it in an alias :
alias prp_indx='
rm cscope.in.out cscope.out cscope.files tags
find . -name '\''*.[chS]'\'' >> cscope.files
find . -name '\''*.cpp'\'' >> cscope.files
find . -name '\''*.hpp'\'' >> cscope.files
find . -name '\''*.cxx'\'' >> cscope.files
find . -name '\''*.hxx'\'' >> cscope.files
cscope -b -q -k; ctags -R
'
Please help me with an appropriate command that I can use in my alias/function to achieve the file names with double quotes without paths broken in many lines.

There is no reason I can think of for find to split a file name on several lines, except if the name itself has newline characters in it.
If you have such file names, it is probably better to rename these files as I think cscope does not really support file names with newlines in them. At least, I don't think there is a way to list such files in a cscope.files file, even with quoting or any kind of escaping (but if you know how to do, please let us know, such that we can adapt what follows accordingly). So, the best you could do is to let cscope do the search (-R) instead of providing a cscope.files file. If you do so cscope will indeed find and analyse these files, but then, when interacting with cscope you will discover that it gets confused and splits the names anyway...
If you do not have such unusual file names, but there are unwanted newline characters in your cscope.files file, there must be something else that tampers with it.
Anyway, prefer a function. Compared to functions, aliases mainly have drawbacks. With a bash function:
prp_indx () {
rm cscope.in.out cscope.out cscope.files tags
find . -name '*.[chS]' -o -name '*.[ch]pp' -o -name '*.[ch]xx' > cscope.files
cscope -b -q -k
ctags -R "$#"
}
Note: if you can have directories with names matching one of the 3 patterns add a -type test to exclude directories:
find . ! -type d \( -name '*.[chS]' -o -name '*.[ch]pp' -o -name '*.[ch]xx' \) > cscope.files
If you have unusual file names containing spaces, double-quotes and/or backslashes, you can add a post-processing with, e.g., sed:
sed -i 's/["\]/\\&/g;s/^\|$/"/g' cscope.files
This will add a backslash before any double-quote or backslash, plus double-quote all file names. Add this sed command to the function definition, after the find command.

Related

Mass Find/Replace within files having specific filename under command line

I am looking for a quick command to search all .htaccess files for a specific IP address and change it to another IP address from the command line
something like
grep -rl '255.255.254.254' ./ | xargs sed -i 's/254/253/g'
I know the above example is a bad way to do it, just an example (and showing I did some searching to find a solution
Search: files with filename .htaccess (within 2 levels deep of current path?)
Find: 255.255.254.254
Replace with: 255.255.253.253
or, is this too much to ask of my server and I would be better off replacing them as I find them?
Try:
find . -type f -name '.htaccess' -execdir sed -i 's/255\.255\.254\.254/255.255.253.253/g' {} +
How it works:
find .
Start looking for files in the current directory.
-type f
Look only for regular files.
-name '.htaccess'
Look only for files named .htaccess.
-execdir sed -i 's/255\.255\.254\.254/255.255.253.253/g' {} +
For any such files found, run this sed command on them.
Because . is a wildcard and you likely want to match only literal periods, we escape them: \.
We use -execdir rather than the older -exec because it is more secure against race conditions.

Linux: how to replace all instances of a string with another in all files of a single type

I want to replace for example all instances of "123" with "321" contained within all .txt files in a folder (recursively).
I thought of doing this
sed -i 's/123/321/g' | find . -name \*.txt
but before possibly screwing all my files I would like to ask if it will work.
You have the sed and the find back to front. With GNU sed and the -i option, you could use:
find . -name '*.txt' -type f -exec sed -i s/123/321/g {} +
The find finds files with extension .txt and runs the sed -i command on groups of them (that's the + at the end; it's standard in POSIX 2008, but not all versions of find necessarily support it). In this example substitution, there's no danger of misinterpretation of the s/123/321/g command so I've not enclosed it in quotes. However, for simplicity and general safety, it is probably better to enclose the sed script in single quotes whenever possible.
You could also use xargs (and again using GNU extensions -print0 to find and -0 and -r to xargs):
find . -name '*.txt' -type f -print0 | xargs -0 -r sed -i 's/123/321/g'
The -r means 'do not run if there are no arguments' (so the find doesn't find anything). The -print0 and -0 work in tandem, generating file names ending with the C null byte '\0' instead of a newline, and avoiding misinterpretation of file names containing newlines, blanks and so on.
Note that before running the script on the real data, you can and should test it. Make a dummy directory (I usually call it junk), copy some sample files into the junk directory, change directory into the junk directory, and test your script on those files. Since they're copies, there's no harm done if something goes wrong. And you can simply remove everything in the directory afterwards: rm -fr junk should never cause you anguish.

Remove special characters in linux files

I have a lot of files *.java, *.xml. But a guy wrote some comments and Strings with spanish characters. I been searching on the web how to remove them.
I tried find . -type f -exec sed 's/[áíéóúñ]//g' DefaultAuthoritiesPopulator.java just as an example, how can i remove these characters from many other files in subfolders?
If that's what you really want, you can use find, almost as you are using it.
find -type f \( -iname '*.java' -or -iname '*.xml' \) -execdir sed -i 's/[áíéóúñ]//g' '{}' ';'
The differences:
The path . is implicit if no path is supplied.
This command only operates on *.java and *.xml files.
execdir is more secure than exec (read the man page).
-i tells sed to modify the file argument in place. Read the man page to see how to use it to make a backup.
{} represents a path argument which find will substitute in.
The ; is part of the find syntax for exec/execdir.
You're almost there :)
find . -type f -exec sed -i 's/[áíéóúñ]//g' {} \;
^^ ^^
From sed(1):
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
From find(1):
-exec command ;
Execute command; true if 0 status is returned. All
following arguments to find are taken to be arguments to
the command until an argument consisting of `;' is
encountered. The string `{}' is replaced by the current
file name being processed everywhere it occurs in the
arguments to the command, not just in arguments where it
is alone, as in some versions of find. Both of these
constructions might need to be escaped (with a `\') or
quoted to protect them from expansion by the shell. See
the EXAMPLES section for examples of the use of the -exec
option. The specified command is run once for each
matched file. The command is executed in the starting
directory. There are unavoidable security problems
surrounding use of the -exec action; you should use the
-execdir option instead.
tr is the tool for the job:
NAME
tr - translate or delete characters
SYNOPSIS
tr [OPTION]... SET1 [SET2]
DESCRIPTION
Translate, squeeze, and/or delete characters from standard input, writing to standard out‐
put.
-c, -C, --complement
use the complement of SET1
-d, --delete
delete characters in SET1, do not translate
-s, --squeeze-repeats
replace each input sequence of a repeated character that is listed in SET1 with a
single occurrence of that character
piping your input through tr -d áíéóúñ will probably do what you want.
Why are you trying to remove only characters with diacritic signs? It probably worth removing all characters with codes not in the range 0-127, so removal regexp will be s/[\0x80-\0xFF]//g if you're sure that your files should not contain higher ascii.

How to use cscope with paths that contain spaces

There are some folder that contains space, and as a result, those folders can not be indexed using cscope.
Can i ask you for help to solve this,or any suggestion.
thanks
Julius
Thanks for your reply.
My steps to use cscope like the following
find . -name '*.scala'>cscope.files
cscope -b
at this step. i see the message indicates that can not find file:
cscope: cannot find file /work/project/copy
cscope: cannot find file of
cscope: cannot find file fp/src/main/jav....
Actually copy of fp is a folder.so i think cscope can not recognize the folder contains space.
I encountered this problem when i tried to use vim with cscope.maybe i need move this question to other tag.
You can do it simply using GNU find at least, you can use the -printf or -fprintf options for that:
find . -type f -fprintf cscope.files '"%p"\n'
pydave's answer is very slow. This way took 0.10s where pydave's answer took 14s:
find . -name "*.scala" | awk '{print "\""$0"\""}' > cscope.files
You can use find's -exec to force quotes around your output:
find . -name "*.scala" -exec echo \"{}\" \; > cscope.files
You might need to mess around with quoting/escaping if you're doing this from a script.
Double quoting the files names works in cygwin, where as escaping with backslash does not.
$ find $PWD -name "*.scala" | sed -e 's/^/"/g' -e 's/$/"/g' > cscope.files

How does one find and copy files of the same extension, in different directories, to a single directory in linux?

So, How Do I find and copy all files,
*.a
that are in,
~/DIR{1,2,3,...}
to
~/tmp/foo?
Assumed you meant recursively copy everything of type .a from some source location.
Haven't verified yet, but this should do that.
find <root-of-search> -type f -name '*.a' -exec cp {} /tmp/foo \;
replace with the top of wherever you want to search from. You might have to throw quotes around *.a, and you might have to replace escape the ending semicolon by putting it in single quotes rather than back-slashing it.
In a bash shell:
cp ~/DIR*/*.a ~/tmp/foo
find ~/DIR{1,2,...} -name *.a print0 | xargs -i -0 cp '{}' ~/tmp/foo

Resources