I want to rename a few files in a folder with one command rather than rename them one by one.
I have a folder named /u0x/XMLs
where there are around 500 folders. Each of these folders has a file named PROCESSED_ADI.XML
. I want to rename all these files to ADI.XML
.
I tried to use find
and -exec mv
together:
XMLs]$ find . -name "*.XML" -exec mv {} ADI.XML \;
After the command was executed all the files have been deleted from the folders or moved from there, which I am not sure. Could someone shed some light on what went wrong and is there any way the files could be retrieved?
CodePudding user response:
After the command was executed all the files have been deleted from the folders or moved from there, which I am not sure
You're renaming the files but the destination or rather the renamed file has a different location, It is the current location/path where you ran the find
command.
You can use -execdir
if your find
supports it.
find . -name "*.XML" -execdir mv -v {} ADI.XML \;
Here is definition of execdir
-execdir command {}
Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find. As with
-exec, the {} should be quoted if find is being invoked from a shell. This a much more secure method for invoking commands, as it avoids race conditions during resolu-
tion of the paths to the matched files. As with the -exec action, the ` ' form of -execdir will build a command line to process more than one matched file, but any given
invocation of command will only list files that exist in the same subdirectory. If you use this option, you must ensure that your $PATH environment variable does not
reference `.'; otherwise, an attacker can run any commands they like by leaving an appropriately-named file in a directory in which you will run -execdir. The same
applies to having entries in $PATH which are empty or which are not absolute directory names. If any invocation with the ` ' form returns a non-zero value as exit sta-
tus, then find returns a non-zero exit status. If find encounters an error, this can sometimes cause an immediate exit, so some pending commands may not be run at all.
The result of the action depends on whether the or the ; variant is being used; -execdir command {} always returns true, while -execdir command {} ; returns true only
if command returns 0.
Here is a bit of demo about what/why did your files got removed deleted.
Let's create a dummy directories and file anywhere but here we will create them in /tmp
cd /tmp
Let's create the directories and files.
mkdir -p u0x/XMLs/folder_{1..10} && touch u0x/XMLs/folder_{1..10}/PROCESSED_ADI.XML
Now check what was created inside those directories, using the tree
command.
tree u0x/
Output
u0x/
└── XMLs
├── folder_1
│ └── PROCESSED_ADI.XML
├── folder_10
│ └── PROCESSED_ADI.XML
├── folder_2
│ └── PROCESSED_ADI.XML
├── folder_3
│ └── PROCESSED_ADI.XML
├── folder_4
│ └── PROCESSED_ADI.XML
├── folder_5
│ └── PROCESSED_ADI.XML
├── folder_6
│ └── PROCESSED_ADI.XML
├── folder_7
│ └── PROCESSED_ADI.XML
├── folder_8
│ └── PROCESSED_ADI.XML
└── folder_9
└── PROCESSED_ADI.XML
11 directories, 10 files
Now we execute your find
command, but with the -v
flag/option.
find u0x/ -name "*.XML" -exec mv -v {} ADI.XML \;
Output
renamed './XMLs/folder_2/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_9/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_7/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_10/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_6/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_3/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_8/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_1/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_4/PROCESSED_ADI.XML' -> 'ADI.XML'
renamed './XMLs/folder_5/PROCESSED_ADI.XML' -> 'ADI.XML'
Now check what happened to the files using the tree
command.
tree u0x/
Output
u0x/
├── ADI.XML
└── XMLs
├── folder_1
├── folder_10
├── folder_2
├── folder_3
├── folder_4
├── folder_5
├── folder_6
├── folder_7
├── folder_8
└── folder_9
11 directories, 1 file
Now If you take a good look at the above output from tree
all of the PROCESSED_ADI.XML
are gone from it's location/folder but there is one ADI.XML
inside the parent directory/folder u0x
Like what was mentioned by @Gordon Davidson All the xml (as long as the file ends in .xml) files has been moved in one location and it was overwritten again and again so now you have only one file named. ADI.XML
Using -execdir
will have the expected output you're looking for.
The output of the tree
command if -execdir
was used, should be:
tree u0x/
u0x/
└── XMLs
├── folder_1
│ └── ADI.XML
├── folder_10
│ └── ADI.XML
├── folder_2
│ └── ADI.XML
├── folder_3
│ └── ADI.XML
├── folder_4
│ └── ADI.XML
├── folder_5
│ └── ADI.XML
├── folder_6
│ └── ADI.XML
├── folder_7
│ └── ADI.XML
├── folder_8
│ └── ADI.XML
└── folder_9
└── ADI.XML
11 directories, 10 files
CodePudding user response:
First of all, do not use a wildcard. Even with -execdir
, you're creating a circumstance where all .XML
files in a directory will be overwritten with the last match in that directory.
find . -type f -name 'PROCESSED_ADI.XML' -exec sh -c 'for i do echo mv "${i}" "$(dirname "$i")/ADI.XML"; done' _ {}
Run this, as a dry run. If it looks ok, remove echo
.