Copy and rename in the same time (also change filename, not only path):
cp program3.cpp homework6.cpp
Rename only:
mv program3.cpp homework6.cpp
Answer from Cornelius on askubuntu.com
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.
linux - How to copy a file to a new file with a new name in same directory but across multiple directories in bash? - Stack Overflow
linux - Copying a file from one directory to the next and changing the name - Unix & Linux Stack Exchange
shell - How can I copy a file in a bash script and rename it while copying and place it in the same directory - Unix & Linux Stack Exchange
How to copy and rename files in shell script - Stack Overflow
Videos
Copy and rename in the same time (also change filename, not only path):
cp program3.cpp homework6.cpp
Rename only:
mv program3.cpp homework6.cpp
If you want to have the files permanently linked use the ln command instead of cp
ln program3.cpp homework6.cpp
This puts a file descriptor (hard link) under the name homework6.cpp to the same file location as program3.cpp
In an -exec predicate, the symbol {} represents a path that is being considered, starting at one of the starting-point directories designated in the command. Example: start/dir2/Preview.json. You can form other file names by either prepending or appending characters, but whether that makes sense depends on the details. In your case, appending produces commands such as
cp start/dir2/Preview.json start/dir2/Preview.jsonQA
which is a plausible command in the event that start/dir2/Preview.json exists. But cp does not automatically create directories in the destination path, so the result of prepending characters ...
cp start/dir2/Preview.json QAstart/dir2/Preview.json
... is not as likely to be accepted -- it depends on directory QAstart/dir2 existing.
I think what you're actually looking for may be cp commands of the form ...
cp start/dir2/Preview.json start/dir2/QAPreview.json
... but find cannot do this by itself.
For more flexibility in handling the file names discovered by find, pipe its output into another command. If you want to pass them as command-line arguments to another command, then you can interpose the xargs command to achieve that. The command on the receiving end of the pipe can be a shell function or a compound command if you wish.
For example,
# Using ./* instead of * ensures that file names beginning with - will not
# be misinterpreted as options:
find ./* -type f -name 'Preview.json' |
while IFS= read -r name; do # Read one line and store it in variable $name
# the destination name needs to be computed differently if the name
# contains a / character (the usual case) than if it doesn't:
case "${name}" in
*/*) cp "${name}" "${name%/*}/QA${name##*/}" ;;
*) cp "${name}" "QA${name}" ;;
esac
done
Note that that assumes that none of your directory names contain newline characters (the read command would split up newline-containing filenames). That's a reasonably safe assumption, but not absolutely safe.
Of course, you would generally want to have that in a script, not to try to type it on the fly on the command line.
If you want to copy Preview.json to a new name like Performance.json, across multiple folders, you can do it like this directly on terminal:
find . -type f -name 'Preview.json' | while read -r file; do \
dir="${file%/*}"; \
cp "$file" "$dir/Performance.json"; \
done
This works like finds every Preview.json in subfolders and copies it to Performance.json in the same folder
For example, If you have .....
./project1/Preview.json
./project2/Preview.json
..... Youβll get
./project1/Performance.json
./project2/Performance.json
Itβs just Bash string slicing:
${file%/*} = everything before the last slash β folder
${file##*/} = just the filename
Check man bash or Google "bash parameter expansion"
No need for bash here, any standard sh interpreter implementation will do:
#! /bin/sh -
ret=0
for file do
dir=$(dirname -- "$file")
case
dir/ # handle / and // specially
esac
base=$(basename -- "$file")
name=${base%.*}
name=${name:-$base} # don't consider .bashrc the extension in /foo/.bashrc
ext=${base#"$name"}
new_file=
{name}_copy
file" "$new_file" || ret=$?
done
exit "$ret"
(assumes the file and dir names don't end in newline characters).
(of course, that will also work with bash since bash is one of those standard sh interpreters.)
For a bash-specific solution, you could try:
#! /bin/bash -
ret=0
re='^((.*/)?[^/])(([^/]*)(\.))?([^/]*)/*$'
for file do
if [[ $file =~ $re ]]; then
if [[ ${BASH_REMATCH[5]} ]]; then
suffix=_copy.${BASH_REMATCH[6]}
else
suffix=${BASH_REMATCH[6]}_copy
fi
cp -- "$file" "${BASH_REMATCH[1]}${BASH_REMATCH[4]}$suffix" || ret=$?
else
printf >&2 '%s\n' "$0: Error: refusing to copy $file"
ret=1
fi
done
exit "$ret"
Since the OP is asking for a bash solution. Here is one that does.
#!/bin/bash
if [[ ! -f $1 && $(($# != 1)) ]]; then
printf '%s\n' "Provide a filename"
exit 1
fi
inFile="$1"
fileExt="${1#*.}"
destFile="${1%.*}"
cp -- "$inFile" "${destFile}_copy.$fileExt" # As suggested, so the files that start with a dash are not ignored.
It's possible without writing a script ("bash file"), but not without using a loop:
for f in *.ext ; do cp -- "$f" "$(basename "$f" .ext)" ; done
basename can be used to remove the suffix.
It's definitely possible without a loop. Is it good ... I'll leave that up to you.
$ find . -type f -name "*.ext" -print0 | xargs -0 -I {} echo cp -T {} {}SUB | sed -e 's/\.extSUB//g'
append a pipe to sh to get out of dry run mode. Backticks are no good as it strips the newlines, unless you deal with $IFS. And there are other character issues with backticks as mentioned. Also need the cp -T as the last argument is normally expecting a directory.
I don't have enough "rep" to comment on the above, but you can use various tricks with bash ${} to avoid the fork of basename.
Substring: ${f:0:-4}
or longest match: ${f%%.ext}
for f in *.html; do cp $f ${f%.html}.php; done
Here you go:
for i in *.html; do mv "$i" "${i%.html}.php"; done
In RedHat Linux and derivatives there is a rename utility that simplifies this to:
rename .html .php *.html
In Debian Linux and derivatives there is a rename utility that simplifies this to:
rename 's/.html$/.php/' *.html
Check man rename or rename --help to see how to use the implementation you have. Sometimes the utility is called rename.pl instead of simply rename.
You can use the following:
for file in *
do
name="${file%.*}"
extension="${file##*.}"
cp $file ${name}_my${extension}
done
Note that ${file%.*} returns the file name without extension, so that from hello.txt you get hello. By doing ${file%.*}_my.txt you then get from hello.txt -> hello_my.txt.
Regarding the extension, extension="${file##*.}" gets it. It is based on the question Extract filename and extension in bash.
If the shell variable expansion mechanisms provided by fedorqui's answer look too unreadable to you, you also can use the unix tool basename with a second argument to strip off the suffix:
for file in *.txt
do
cp -i "$file" "$(basename "$file" .txt)_my.txt"
done
Btw, in such cases I always propose to apply the -i option for cp to prevent any unwanted overwrites due to typing errors or similar.
It's also possible to use a direct replacement with shell methods:
cp -i "$file" "${file/.txt/_my.txt}"
The ways are numerous :)