renaming the files recursively in unix - unix

i know this would be marked as a duplicate one, but i tried searching google and what i'm trying is not working for me.
I've some .txt files in a directory, i need to rename all the *.txt files to *_XYZ.txt recursively. XYZ is defined in a variable X.
I've tried below code:
file=`find ./ -type f -name "*.txt"|sed "s,^./,,g" |awk -F '.' '{print $1}'`
for i in "$file"
do
mv "$i" "$i_${X}.txt"
done
Any help would be greatly appreciated.
Thanks.

Your script destroys original filenames in variable file, this is why it cannot rename files.
Working example:
X="_XYZ"
for f in $(find . -type f ! -name "*$X.txt" -name "*.txt"); do
mv "$f" "${f%.txt}$X.txt"
done
Output:
$ X="_XYZ"
$ find . -type f -name "*.txt"
./c_XYZ.txt
./aa/c.txt
./a.txt
./b.txt
$ for f in $(find . -type f ! -name "*$X.txt" -name "*.txt"); do mv "$f" "${f%.txt}$X.txt"; done
$ find . -type f -name "*.txt"
./b_XYZ.txt
./c_XYZ.txt
./aa/c_XYZ.txt
./a_XYZ.txt

Related

unix find command in terminal does not work

I need to place a command that will search for all files in the current directory as well as in its sub-directories - ending by ~, and/or all files that start or end by #. The command line will show and erase all files found. Only one command is allowed: no ’;’ or ’&&’ or other shenanigans.
here is my command:
find . -name "#*" -o -name "*#" -o -name "*~" -print -delete
but it erases only the files ending in ~
You forgot to enclose the conditions with parenthesis (). This means that only the last condition will trigger the actions -print and -delete.
The default is and -a, which would not require the parenthesis, that's why most find commands such as find -type f -name "pattern" -print works without parenthesis.
You should try:
find . \( -name "#*" -o -name "*#" -o -name "*~" \) -print -delete
How about -print0 primary in conjunction with xargs -0'' like this .
find . -type f -print0 | xargs -0 rm
za:temp za$ ls
file.txt file.txt~
za:temp za$ find . -name "*~" -print0 | xargs -0 rm
za:temp za$ ls
file.txt
Or with xargs -I {} plus your comand which does the same thing .
# xargs -I {} to capture the value of find
find . -iname *something* | xargs -I {} rm {}
edit : if you can't see the files that start with # using find . then the files have spaces within the name of the file(s) like # file.txt. you will need to find files with spaces with something like find . -name "* *" and then remove the spaces.

How do you move all files and folders within a directory to the parent directory?

How do you move all files and folders within a directory from their sub directories to the parent directory? Including files within very deep folder directories.
What I would like to achieve is for when I am at . to convert this:
.
./aDir
./aDir/bFile
./aDir/cDir
./aDir/cDir/dDir
./aDir/cDir/dDir/eFile
To this:
.
./aDir
./bFile
./cDir
./dDir
./eFile
I assume you use the unix command find however I can't seem to get it to work.
Here's what I tried:
find -mindepth 1 -maxdepth * -print0 | xargs -0 mv -i -t ~/Desktop
Since you are looking to un-nest your directory you'll need to mv them in depth first order, otherwise deeper directories could be mv'd inside the shallower ones.
Using very similar syntax to your attempt the following seems to do what is required.
find . -mindepth 2 -depth -type d -print0 | xargs -0 -I{} mv {} ~/Desktop
Example:
$ find . -mindepth 1 -depth -type d
./a/b/c2
./a/b/c
./a/b
./a
$ find . -mindepth 2 -depth -type d -print0 | xargs -0 -I{} mv {} .
$ find . -mindepth 1 -depth -type d
./a
./b
./c
./c2
Maybe this helps:
for i in $(find .); do cp -r $i .; done
When you are at . it converts this:
.
./a
./a/b
./a/b/c
To this:
.
./a
./a/b
./a/b/c
./c
./b
./b/c
Try this
find . -maxdepth 1 -exec mv {} .. \;
you might get this message
mv: cannot move `.' to `../.': Device or resource busy
But don't worry it is because '.' this directory is being attempted to move.
I think you want:
find . -mindepth 1 -depth -print0 | xargs -0 mv -i -t ~/Desktop

Bash, find and delete whilst retaining directory

I am trying my hand at some Bash scripting and any help would be appreciated.
The script is supposed to find all users users in /Users/ and delete everything inside. Movies, Documents, Desktop and Music.
Whilst still retaining the directory essentially emptying it. Also excluding the user files of ladmin, shared and Guest.
When I execute. It doesn't empty the files though I get the feed back I would expect. Am I missing something simple here?
DIR_CD=/Users/
cd $DIR_CD
find . -type d ! -name "*ladmin*" ! -name "*Guest*" ! -name "*Shared*" \
-maxdepth 1 -print -exec rm -rf {}/Desktop/* \;
find . -type d ! -name "*ladmin*" ! -name "*Guest*" ! -name "*Shared*" \
-maxdepth 1 -print -exec rm -rf {}/Documents/* \;
find . -type d ! -name "*ladmin*" ! -name "*Guest*" ! -name "*Shared*" \
-maxdepth 1 -print -exec rm -rf {}/Movies/* \;
find . -type d ! -name "*ladmin*" ! -name "*Guest*" ! -name "*Shared*" \
-maxdepth 1 -print -exec rm -rf {}/Music/* \;
Like this?
for d in /Users/*; do
case ${d#*/} in ladmin | Guest | Shared ) continue ;; esac
rm -rf "$d"/Desktop/* "$d"/Documents/* "$d"/Movies/* "$d"/Music/*
done
With Bash extended globbing you could do it all with a single wildcard expression.

Collect .txt and .log files using find

I currently have this script to compress log files:
find . -name '*.log' -print0 | xargs -0 tar zcf $file
Currently finds and compress all the *.log files. I would like to modify it to include also all the ".txt" files but I don't know how, this should be fairly simple right?
find . -type f \( -name "*.log" -o -name "*.txt" \) -exec tar zcf "$file" {} +
Alternatively:
find . -type f -regex ".*\.\(txt\|log\)$" -exec tar zcf "$file" {} +
No need for xargs if your version of find is POSIX compliant and can have it's -exec command terminated with a + (most can)

How to use find command to find all files with extensions from list?

I need to find all image files from directory (gif, png, jpg, jpeg).
find /path/to/ -name "*.jpg" > log
How to modify this string to find not only .jpg files?
find /path/to -regex ".*\.\(jpg\|gif\|png\|jpeg\)" > log
find /path/to/ \( -iname '*.gif' -o -iname '*.jpg' \) -print0
will work. There might be a more elegant way.
find -E /path/to -regex ".*\.(jpg|gif|png|jpeg)" > log
The -E saves you from having to escape the parens and pipes in your regex.
find /path/to/ -type f -print0 | xargs -0 file | grep -i image
This uses the file command to try to recognize the type of file, regardless of filename (or extension).
If /path/to or a filename contains the string image, then the above may return bogus hits. In that case, I'd suggest
cd /path/to
find . -type f -print0 | xargs -0 file --mime-type | grep -i image/
find /path -type f \( -iname "*.jpg" -o -name "*.jpeg" -o -iname "*gif" \)
On Mac OS use
find -E packages -regex ".*\.(jpg|gif|png|jpeg)"
In supplement to #Dennis Williamson 's response above, if you want the same regex to be case-insensitive to the file extensions, use -iregex :
find /path/to -iregex ".*\.\(jpg\|gif\|png\|jpeg\)" > log
find -regex ".*\.\(jpg\|gif\|png\|jpeg\)"
in case files have no extension we can look for file mime type
find . -type f -exec file -i {} + | awk -F': +' '{ if ($2 ~ /audio|video|matroska|mpeg/) print $1 }'
where (audio|video|matroska|mpeg) are mime types regex
&if you want to delete them:
find . -type f -exec file -i {} + | awk -F': +' '{ if ($2 ~ /audio|video|matroska|mpeg/) print $1 }' | while read f ; do
rm "$f"
done
or delete everything else but those extensions:
find . -type f -exec file -i {} + | awk -F': +' '{ if ($2 !~ /audio|video|matroska|mpeg/) print $1 }' | while read f ; do
rm "$f"
done
notice the !~ instead of ~
Adding -regextype posix-extended option only worked in my case:
sudo find . -regextype posix-extended -regex ".*\.(css|js|jpg|jpeg|png|ico|ttf|woff|svg)" -exec chmod 0640 {} \;

Resources