Files With Spaces Are Treated As Seperate Files - find

How can I modify the script to not treat files with spaces as separate files?
thetime=`date +%Y-%m-%d_%H:%M:%S` #
for i in $(find . ! -name "*.filepart")
do
extn=${i##*.} # save the extension of the file
mv "$i" "${i%.*}"$(date "+_%Y-%m-%d_%H:%M:%S.${extn}")
done
mv: cannot stat ‘./user1/upload/Axle’: No such file or directory
mv: cannot stat ‘Assy’: No such file or directory
mv: cannot stat ‘Removal.doc’: No such file or directory
#find . ! -name "*.filepart"
#./user1/upload/Axle Assy Removal.doc

This won't work with files whose names contain whitespace:
for i in $(find . ! -name "*.filepart"); do # Fail
The following two methods will work for all file names:
Method 1: Use -execdir
find . -type f ! -name "*.filepart" -execdir sh -c 'f=$(basename "$1"); mv "./$f" "./${f%.*}$(date "+_%Y-%m-%d_%H:%M:%S")${f#${f%.*}}"' Mv {} \;
Method 2: Use -print0
find . -type f ! -name "*.filepart" -print0 | while IFS= read -r -d $'\0' file
do
d=$(dirname "$file")
f=${file#$d}
mv "$d$f" "$d${f%.*}$(date "+_%Y-%m-%d_%H:%M:%S")${f#${f%.*}}"
done
Further reading
How can I find and safely handle file names containing newlines, spaces or both?

Related

sed is appending code in the wrong place in all but one file in a directory

I have the following tab indented code in a bunch of files in a directory:
'oracleServers': dcoDatabaseServers,
'oracleHomes': dcoDatabaseHomes,
'sysPasswords': dcoSYSPasswords,
I want to add 'useOracleDriver': useOracleDriver, after the 'oracleHomes' line in all files. I have this command:
sed -i "/oracleHomes/ a \\\t\t\t\t\t\t\t\t'useOracleDriver': useOracleDriver," $(find . -type f -name 'tc*')
When I run the command, the first file in alpha order with a tc* name, the text gets appended properly:
'oracleServers': dcoDatabaseServers,
'oracleHomes': dcoDatabaseHomes,
'useOracleDriver': useOracleDriver,
'sysPasswords': dcoSYSPasswords,
but with all other files beginning with tc*, I see the 'useOracleDriver': useOracleDriver line, but it's appended to the very end of the file. Any idea on how to get the command to append in the proper place in all the other files?
Try running the sed command on each file individually, instead of all on a single sed execution:
find . -type f -name 'tc*' -exec sed -i "/oracleHomes/ a \\\t\t\t\t\t\t\t\t'useOracleDriver': useOracleDriver," {} \;
or
for f in $(find . -type f -name 'tc*'); do sed -i "/oracleHomes/ a \\\t\t\t\t\t\t\t\t'useOracleDriver': useOracleDriver," $f; done
The advantage of the second format is that, in the event you're not using GNU sed (and therefore have no -i), you can change it to
for f in $(find . -type f -name 'tc*'); do sed "/oracleHomes/ a \\\t\t\t\t\t\t\t\t'useOracleDriver': useOracleDriver," $f > $f.tmp; mv $f.tmp $f; done

Files not available after running find command

I tried to rename files ending with ".txt" to ".abc" using the find command as below. Now the files are not available on my disk.
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$1.abc"' {} \;
can someone explain me the above command in detail what is did with the files.
Is there any possibility to retrive those, if yes how ?
You used the wrong variable and most of the files cannot be retrieved.
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$1.abc"' {} \;
will rename every .txt file to a file called .abc. So if you files named bar.txt and foo.txt it will rename bar.txt to .abc and then rename foo.txt to .abc which will overwrite the original contents of bar.txt. You cannot see the file because it is .abc and is hidden under a normal list. If you run 'ls -a' you will see a file named ".abc" which will have the contents of the last .txt file that was renamed.
I am not sure how to do exactly what you wanted but running
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$0.abc"' {} \;
will rename each .txt file to a .txt.abc file. So you would have bar.txt.abc and foo.txt.abc
The explanation of rondo is correct.
But what are the solutions for your problem?
If you want to replace the suffix .txt with .abc you can use rename
You will have success, if you use rename and find like this:
find . -type f -iname '*.txt' -print0 | xargs -0 rename .txt .abc
For all files found by find like x.txt or a/b.txt the appropriate command will execute, e.g.
rename .txt .abc x.txt
rename .txt .abc a/b.txt
so x.txt -> x.abc, and a/b.txt -> a/b.abc
If you only want to add the suffix .abc to all files you can still use mv
find . -type f -iname '*.txt' -print0 | xargs -0 mv {} {}.abc
With xargs for each file the command mv is executed.
BTW: with the find option "-print0" and the xargs option "-0" the commands work also with filenames which includes spaces.

How to copy a file on several directories with the name *Co* (where *=wildcard)

How to copy a file to several directories of the form *Co*? or *52?
Apparently, just typing
cp fileA *Co*
won't work.
My other concern is that if a directory already contains fileA, I don't want it to be overwritten. That is, if the directory *Co* contains fileA, do NOT copy. Is there a one line solution for this, since I think writing a script with if-else is an overkill.
Thanks!
If your version of cp supports -n, you can do:
find . -name '*Co*' -exec cp -n fileA {} \;
If not:
find . -name '*Co*' -exec sh -c 'test -f $0/fileA || cp fileA $0' {} \;
Note that these will each descend recursively: if you don't want that you can limit the scope of find. To find either Co or *52, you can do:
find . \( -name '*Co*' -o -name '*52' \) -exec ...

Find executable files, also those NOT marked executable

How to Find binary files with or without executable permissions?
I am working on a BASH script that would list in a path:
* Shared Object files,
* scripts, executable files,
* static libraries
It should not display intermediate files like .o (object files).
You can use:
find . -type f -print0 | xargs -0 -n 10 file -i | grep "application/x-executable"
The file program reports file type based on contents, so
file /bin/* | awk -F: '/executable/{print $1}'
reports potentially/actually executable files in /bin.
This worked for me & thought of sharing...
find ./ -type f -name "*" -not -name "*.o" -exec sh -c '
case "$(head -n 1 "$1")" in
?ELF*) exit 0;;
MZ*) exit 0;;
#!*/ocamlrun*)exit0;;
esac
exit 1
' sh {} \; -print

How to create links to all subfolders containing specified text in their names

As specified in title I am looking for a way how to create links to all subfolders containing specified text in their names, so for example for all subfolders of root directory containing ".app" in their names an link will be created to "/AppLinks" directory. I would like to use it in bash script (open source, free).
Does anyone know how to do that?
I searched it by google with no luck.
find yourdir -type d -name '*.app' -exec ln -s {} /AppLinks \;
Find all directories named something.app in yourdir, and create a symlink to them in /AppLinks.
single line bash-fu
function FUNCsymlink() { echo "$1"; fileName=`basename "$1"`; ln -s "$1" "/AppLinks/$fileName"; }; export -f FUNCsymlink; find `pwd`/ -maxdepth 1 -type d -iname "*.app" -exec bash -c "FUNCsymlink '{}'" \;
to easy reading:
function FUNCsymlink() {
echo "$1";
fileName=`basename "$1"`;
ln -s "$1" "/AppLinks/$fileName";
};
export -f FUNCsymlink;
find `pwd`/ -maxdepth 1 -type d -iname "*.app" -exec bash -c "FUNCsymlink '{}'" \;
you may have to adjust it a bit for your specific solution.
wherever you run it, it will create the symlinks to /AppLinks
it will only look for direct subfolders, not subfolders of subfolders, thats what I believe you need..