Home > database >  does exec mv command used with find deletes the files?
does exec mv command used with find deletes the files?

Time:11-13

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.

  • Related