Script that replaces all "*.html" file names with "*.html.<username>" - shell

Write a script that replaces all *.html file names with *.html.<username> in the current directory.

You could use find's -exec option:
$ find . -name "*.html" -exec mv '{}' '{}'.${USER} \;

If you have perl-rename installed (called rename on Debian-based and many other systems, /usr/bin/site_perl/rename on others), you can run:
rename "s/\.html$/.html.$USER/" *
If you don't have the perl rename, but have the compiled one, you can do:
rename '.html' ".html.$USER" *
If you have neither, use the shell:
for f in *.html; do mv "$f" "$f"."$USER"; done

Related

Change of directories names according to pattern in Bash

I need to change with one-liner (best option) directories name, more precise - to remove some prefix that has variable part at the beginning TO_BE_REMOVED_W._
I can find dirs to modification with:
find ./ -type d -iname 'TO_BE_REMOVED_W*' -exec mv {} _____ \;
How should I form execution part to rename directories to remove pattern from whole name?
Most distros come with rename which accepts substitution patterns, so I usually use -execdir with rename.
For example, to remove PREFIX_:
$ find . -execdir rename 's/^PREFIX_//' '{}' +
Note that for Arch Linux, this is called perl-rename (Arch's default rename is not the standard rename found on most distros).
You can use -exec bash -c '...' like this:
$ find -name 'foo*'
./foo-01
./foo-05
./foo-02
./foo-03
./foo-04
$ find -name 'foo*' -exec bash -c 'file=$0; echo Now you can do anything with $file ...' {} \;
Now you can do anything with ./foo-01 ...
Now you can do anything with ./foo-05 ...
Now you can do anything with ./foo-02 ...
Now you can do anything with ./foo-03 ...
Now you can do anything with ./foo-04 ...
$

How to delete a file except in any one of the subdirectory using shell script

Hi I want to delete a file from any of the subdirectories except one of the subdirectory.
For ex
folder a->a.txt
folder b->subdir 1 -> msgdir-> a.txt
folder c->
Now i want to delete a.txt only in folder a but not the file in msgdir .msgdir can be in any level of subdirectories as it would be changing.
Please help me to resolve this.
This will ignore specifically the msgdir at any level and remove a.txt except in msgdir.
find . ! -path '*/msgdir/*' -name a.txt -type f -delete
Tested with GNU find 4.4.2 and BSD find (Mac Yosemite).
The following approach is overkill if you have GNU find (or a newer BSD one), with the -path option. Otherwise, read on...
You haven't specified which shell you're using but if you have bash, you could go with something like this:
find -name a.txt -exec bash -c "[[ '{}' != */msgdir/* ]]" \; -print
This filters out paths containing /msgdir/, as the test will only pass if the file path doesn't contain the string. If you're happy with the results, you can change -print to -delete.
Without bash, you could use grep to determine the match:
find -name a.txt -exec sh -c "printf '%s' '{}' | grep -qv '/msgdir/'" \; -print

How to print the deleted file names along with path in shell script

I am deleting the files in all the directories and subdirectories using the command below:
find . -type f -name "*.txt" -exec rm -f {} \;
But I want to know which are the files deleted along with their paths. How can I do this?
Simply add a -print argument to your find.
$ find . -type f -name "*.txt" -print -exec rm -f {} \;
As noted by #JonathanRoss below, you can achieve an equivalent result with the -v option to rm.
It's not the scope of your question, but more generally it gets more interesting if you want to delete directories recursively. Then:
a simple -exec rm -r argument keeps it silent
a -print -exec rm -r argument reports the toplevel directories you're operating on
a -exec rm -rv argument reports all you're removing

Rename files with dynamic name in bash

I am trying to rename all files which contains 'Name' with dynamic name.
So this file 'NameSomething' should look like this 'SearchSomething'. But script below just removes 'Name' from file name.
name='search'
Name='Search'
find ../../$name-module -name 'Name*' -type f -exec bash -c 'mv "$1" "${1/Name/$Name}"' -- {} \;
You have to export Name, because otherwise the command find will not inherit the variable $Name into its environment. So:
name='search'
export Name='Search'
find ../../$name-module -name 'Name*' -type f -exec bash -c 'mv "$1" "${1/Name/$Name}"' -- {} \;
\You can escape quotes, no need for an export:
find ../../$name-module -name 'Name*' -type f -exec bash -c "mv \"\$1\" \"\${1/Name/$Name}\"" -- {} \;
You might use find to find a list of the files you want to rename and pipe that to another program to do the renaming.
For example, you could do:
find ../../$name-module -print0 -name 'Name*' -type f | \
xargs -0 rename "s/Name/$Name/"
No need for exporting (ugly + might affect other commands)
Rename might get run only once (if all the found files fit on one command line) (with -exec, you're running two programs -- bash and mv -- per each file. That might be inefficient.
(You could get further performance increase with this approach by using Gnu parallel instead of xargs, if you're on a multicore computer)
You could use the Perl-based rename command:
Name=Search
rename "s/^Name/$Name/" *

batch rename file extensions in subdirectories

I'm trying to create a batch file in linux that will allow me to change extensions of files in multiple subdirectories. After much searching and experimenting i've found what seems to be a solution:
find /volume1/uploads -name "*.mkv" -exec rename .mkv .avi {} +
When running the script i get the following error:
find: -exec CMD must end by ';'
I've tried adding ; and \; (with or without +) but to no avail. What's wrong with the command and how can I fix it?
Edit: Running on a Synology NAS with DSM 4.2
you have to escape all characters that would be interpreted by bash. in your case these are the semicolon and the curly braces (you forgot to escape the latter in your code):
find /volume1/uploads -name "*.mkv" -exec rename .mkv .avi \{\} \;
the {} (in our case \{\}) is expanded to the filename, so the actual call would look like rename .mkv .avi /volume1/uploads/foo/bla.mkv (which is not the exact syntax the /usr/bin/rename needs, at least on my system).
instead it would be something like:
find /volume1/uploads -name "*.mkv" -exec rename 's/\.mkv$/.avi/' \{\} \;
UPDATE
if you don't want to (or cannot) use perl's rename script, you could use the following simple bash script and save it as /tmp/rename.sh
#!/bin/sh
INFILE=$1
OUTFILE="${INFILE%.mkv}.avi"
echo "moving ${INFILE} to ${OUTFILE}"
mv "${INFILE}" "${OUTFILE}"
make it executable (chmod u+x /tmp/rename.sh) and call:
find /volume1/uploads -name "*.mkv" -exec /tmp/rename.sh \{\} \;
UPDATE2
it turned out that this question is really not about bash but about busybox.
with a limited shell interpreter like busybox, the simplest solution is just to append the new file extension:
find /volume1/uploads -name "*.mkv" -exec mv \{\} \{\}.avi \;
Not sure how different find and rename commands are on your DSM 4.2 OS so try something like:
find /volume1/uploads -name "*.mkv" | while read filename;
do mv -v "${filename}" "$(echo "${filename}" | sed -e 's/\.mkv$/\.avi/')"
done

Resources