why are you using ls with an extra process to while loop? Just use a for loop with shell expansion. This is preferred way
#!/bin/bash
shopt -s nullglob
for file in *
do
if [ -f "$file" ];then
newfile="${file##* }"
mv "$file" $newfile"
fi
done
Answer from ghostdog74 on Stack Overflow
This is a pretty basic question but Iโve been struggling getting this working for some reason. I am trying to copy a file from one directory to another and renaming it along with the copy. This is being done inside of a shell script, and I have a variable called $filename that stores the NEW file name. Here is the code snippet:
filename="IRcam_fpga_cksm_${checksum}_ver_${version}.pdb"
#filename="This_is_a_file.txt"
echo "filename: ${filename}"
cp ./par/ircam_fpga/designer/impl1/*.pdb output/pl/$filenameThe output of the echo command on the console is:
.pdbname: IRcam_fpga_cksm_A415_ver_0x0081
But the file that gets copied to the new directory does not have the correct name. When I use the version of $filename that is commented out, it works perfectly fine.
why are you using ls with an extra process to while loop? Just use a for loop with shell expansion. This is preferred way
#!/bin/bash
shopt -s nullglob
for file in *
do
if [ -f "$file" ];then
newfile="${file##* }"
mv "$file" $newfile"
fi
done
Postman almost has it. For rename.sh, the awk command returns nothing so in effect you have the following command the shell attempts to execute:
mv rename.sh
hence the error message "missing destination file"
you can fix this by testing for the filename of the script, either hardcoded or $0, and executing the mv command only if $FILE does equal the script name.
Rename multiples files using Bash scripting - Unix & Linux Stack Exchange
bash - Rename all files in directory from $filename_h to $filename_half? - Stack Overflow
shell script - rename files with rename command - Unix & Linux Stack Exchange
How to copy and rename files in shell script - Stack Overflow
Videos
#!/bin/bash
cd $1
for f in *; do
mv "$f" "${f%.*}.bu"
done
Try that instead (assuming that $1 is a folder):
for f in
f" "$f.bu"
done
Or use the rename utility:
rename -v 's/$/\.bu/' $1/*
Those commands add an extension. If you want to change the existing extension use that:
rename -v 's/\.[^\.]+$/\.bu/' $1/*
You were right to consider rename first. The syntax is a little strange if you're not used to regexes but it's by far the quickest/shortest route once you know what you're doing:
rename 's/\d{4}/2503/' file*
That simply matches the first 4 numbers and swaps them for the ones you specified.
And a test harness (-vn means be verbose but don't do anything) using your filenames:
$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p
This should do the trick:
for f in file*; do mv
{f/${f:4:8}/25032014}; done
It replaces the string beween the 4th and the 12th character with "25032014".
Just use bash, no need to call external commands.
for file in *_h.png
do
mv "$file" "${file/_h.png/_half.png}"
done
Do not add #!/bin/sh
For those that need that one-liner:
for file in *.png; do mv "$file" "${file/_h.png/_half.png}"; done
Try rename command:
rename 's/_h.png/_half.png/' *.png
Update:
example usage:
create some content
$ mkdir /tmp/foo
$ cd /tmp/foo
$ touch one_h.png two_h.png three_h.png
$ ls
one_h.png three_h.png two_h.png
test solution:
$ rename 's/_h.png/_half.png/' *.png
$ ls
one_half.png three_half.png two_half.png
If you want to process files only in the top level of the directories (ie: one level deep), then you don't need recursion.
Both of these examples take a list of directories as arguments and rename only the files in those directories which match the more exclusive pattern: *-*.png (to avoid possible failures of the mv command).
A script that does NOT change directory:
In this first script, inside the for loop, the variable name contains the directory path to the file in addition to the base filename.
#!/bin/sh
for dir in "$@"
do
for name in "$dir"/*-*.png
do
mv "$name" "${name%-*}.png"
done
done
A script that DOES change directory:
In this second script, inside the for loop, the name variable contains only the filename, because the current directory has been temporarily changed to the script argument.
The code between the parenthesis ( and ), is executed in a subshell environment which means that changing the current directory, as well as variables set, will not be visible to the outer shell script, eliminating the need to change "back" to the original directory.
#!/bin/sh
for dir in "$@"
do
(
if cd "$dir"
then
for name in ./*-*.png
do
mv "$name" "${name%-*}.png"
done
fi
)
done
Notes About These Two Scripts:
The "$@" expands to the script's command line arguments. The script will silently do nothing with no arguments.
The directory-name arguments can be any absolute path (/path/to/dirx) or relative path (dirx, path/to/diry, ., .., ../x/d1, etc).
Messages will be printed on the standard error stream (stderr) by either mv or cd if a given directory does not exist, or if there are no *-*.png files in a directory. The script will continue processing subsequent directories.
The first line of these scripts can be #!/bin/sh instead of bash because this script uses none of the bash features, thus the more portable, posix compliant, and probably faster, sh can be used. Few scripts require the extra features of the bash shell. For these and other reasons #!/bin/bash is not generally recommended for scripting.
This worked for me
for dir in *; do if cd $dir; then for filename in *; do mv $filename "$filename.pdf"; done; cd ..; fi; done
Temporary note: there is something wrong - the rename pattern does not handle filenames with path; I'm working on a fix
What is wrong in your command is two things:
find /tmp/dir -name "* *" -type f | rename 's/*/fixed_/g'
The
-name "* *"matches only file names with a space in it - that's not what you want, right?- the solution is to just leave it out; We do not want to exclude files matching some name - we want all.
The
renamepattern is wrong in two ways- you used a shell glob pattern, but it needs to be a regular expression, in short a regex (It can be some general perl expression - let's ignore it and use only
s///g) - the fixed pattern would match the complete name, and replace it with
fixed_. You want to "replace" the "first 0 characters" withfixed_, technically. That's the start of the line, matched with^. We can leave out thegbecause there is only one replacement needed per line.
- you used a shell glob pattern, but it needs to be a regular expression, in short a regex (It can be some general perl expression - let's ignore it and use only
Putting it together, it looks like this:
find /tmp/dir -type f | rename 's/^/fixed_/'
It seems your system features the older version of rename that doesn't use regular expressions. You can rename your files with
cd /tmp/dir/
for f in *\ * ; do
[[ -f $f ]] && mv "$f" fixed_"$f"
done
(untested)
For the rename command with regex support, you have to change the regular expression: * needs something to operate on, it means "repeat the previous thing zero or more times". You don't want to replace anything, you want to prepend, so use ^ which stands for the beginning of the string:
rename 's/^/fixed_/'
An example to help you get off the ground.
for f in *.jpg; do mv "$f" "$(echo "$f" | sed s/IMG/VACATION/)"; done
In this example, I am assuming that all your image files contain the string IMG and you want to replace IMG with VACATION.
The shell automatically evaluates *.jpg to all the matching files.
The second argument of mv (the new name of the file) is the output of the sed command that replaces IMG with VACATION.
If your filenames include whitespace pay careful attention to the "$f" notation. You need the double-quotes to preserve the whitespace.
You can use rename utility to rename multiple files by a pattern. For example following command will prepend string MyVacation2011_ to all the files with jpg extension.
rename 's/^/MyVacation2011_/g' *.jpg
or
rename <pattern> <replacement> <file-list>
To do this in a single command, you can simply do this:
mv some/long/path/to/file/{myfiel.txt,myfile.txt}
Which is an example for the full file name, given that it's a typo you can do something like:
mv some/long/path/to/file/myfi{el,le}.txt
Both will expand to the full command, these are called brace expansions. They are supported by zsh.
Here are several options:
Change to the directory:
cd /home/long/path
mv file1 file2
cd -
Change directories using the directory stack:
pushd /some/long/path
mv file1 file2
popd
Change to the directory using a subshell:
(
cd /some/long/path
mv file1 file2
) # no need to change back
Use brace expansion:
mv /some/long/path/{file1,file2}
Use a variable:
D=/some/long/path
mv "$D/file1" "$D/file2"