You never answered the question of whether a file named filexfile.txt
should be moved to newfilexfile.txt
or to newfilexnewfile.txt
. And, I'm disappointed that you didn't try to rewrite your code based on the comments I provided in post #2 in this thread. But, I did make (at least) one mistake in that post. If you run the command:
mv file1 file2
where file1 and file2 are the same and name an existing file or if file1 and file2 are different but both names are pathnames that refer to the same file (because they are linked together), the standards require that one of three things happen:
- the request is silently ignored,
- a diagnostic message is printed, no change is made to the file, and the final exit status of
mv
will be non-zero, or
- if the two operands are distinct (but name the same file), the file1 will be removed. (Note that if file2 is a symbolic link pointing to file1 and file1 is not a symbolic link, this may result in the loss of your data.)
Note that none of the suggestions that have been posted in this thread (including the two suggestions below) make any attempt to verify that the new pathname you want to use is not linked to the current pathname. The code below at least makes sure that when mv
is invoked, the two operands won't be the same string. If there is a chance that the old and new names you are trying to create for a file could refer to the same file, I leave it to you to make adjustments to the code if any system on which you run your script has a mv
utility that does not behave the way you want it to behave.
If you really don't want to use the shell's "${path/file/newfile}"
variable expansion because it is not in the standards yet or because you really do want to be able to replace multiple occurrences of file
with newfile
if you run into a pathname containing multiple occurrences of that string, and you really want to use
awk
or
sed
to solve this problem; at least consider something like the following so you aren't invoking awk
or sed
and a shell for each pathname you process and so you don't invoke mv
to move a file whose name won't change because it didn't contain the string file
to begin with:
#!/bin/bash
set -vx
for path in ~/Shell_Practice/rename/*file*.txt
do [ -e "$path" ] && printf '%s\n' "$path"
done | awk '
{ old = $0
gsub(/file/, "newfile")
print "echo mv --", "\""old"\"", "\""$0"\""
}' | bash -xv
or (preferably):
#!/bin/bash
set -vx
for path in ~/Shell_Practice/rename/*file*.txt
do [ -e "$path" ] && printf '%s\n' "$path"
done | sed 'p; s/file/newfile/g' | while read -r oldpath && read -r newpath
do echo mv -- "$oldpath" "$newpath"
done
If one of these prints the mv
commands you want to invoke, remove the word echo
from the script and run it again to actually rename the files.
Obviously, the awk
script could also be rewritten to get rid of the second invocation of bash
. I will leave doing that set of trivial changes as an exercise for the reader.