0

I have thousands of text files called file.txt. Because they all share the same name I cannot move them to the same folder without them overwriting.

I need a command that will locate all of the file.txt files that are within thousands of directories and subdirectories, append the full path name to the end of the file name and then copied to a specified folder leaving the original where it was.

example:

from: file.txt 
to: a/123/file.txt

(i know / cant be used in a file name so hyphens or underscores will work, unless there is a visually more appropriate replacement)

Also, the command would need to ignore case as some are file.txt and some are File.txt as well have an optional 'S' on the end (file.txt or files.txt).

During the renaming, I am hoping the path can be appended as is, without changing case as the directory/subdirectory names are randomized (example: a/adgDGeRddsdvvsdGSD/[fF]ile[s].txt

Thanks!

0

2 Answers 2

1

Using find and a shell script to convert the paths to relative paths to the start directory and replacing / with _:

find . -type f -iname 'file*.txt' -exec sh -c '
    targetdir=$1; shift
    for file; do
        cp "$file" "$targetdir/$(realpath --relative-base=. "$file" | tr '/' '_')"

        # uncomment to restrict the filename to the last 4 directories
        #cp "$file" "$targetdir/$(realpath --relative-base=. "$file" | 
        #   rev | cut -d'/' -f-5 | rev | tr '/' '_')"
    done
' sh /tmp/dest {} +

Replace /tmp/dest with your target directory and cd to the parent directory of your files before running the command.

Example input directory structure:

.
├── dir1
│   ├── file.txt
│   └── sub1
│       └── file.txt
├── dir2
│   └── file.txt
└── file.txt

Output in /tmp/dest:

dir1_file.txt
dir1_sub1_file.txt
dir2_file.txt
file.txt
11
  • Hey this works great! i just want to ask if you can incorporate two more things into the command. 1. if there is some text before file.txt can the command still look for those files? will it combine them or will they be separate? and 2. when moving the files to the destination directory, is there a way to concatenate files if the exact file name exists? lastly, if i want it to just find .txt files without specifying a name is there a way to do that? Commented Feb 28, 2023 at 17:57
  • 1. Yes, just use '*file*.txt', I just don't understand the "combine" question. Each input filename should have one output filename (unless there are input files with underscores). 2. Why? Each file should already have one destination filename. I thought you don't want to concatenate the files any more.
    – Freddy
    Commented Feb 28, 2023 at 18:08
  • for 2. sometimes updated versions of these txt files come in later. since the destination is the same they would have the same file name and the newer one would overwrite the older one. the information could be entirely different and it would be beneficial to keep all data instead of just the most recent version of a file. Commented Feb 28, 2023 at 18:11
  • as for the end of my comment of just trying to get any .txt file, i get this response "paths must precede expression" when trying '*.txt" it seems i cant just use an asterisk and have to have some text. Commented Feb 28, 2023 at 18:14
  • You could change cp "$file" to cat "$file" >> to append each file, but this would also append if no input file was changed. You wouldn't know. And you also wouldn't know where the end of the previous file and the beginning of the new file would be. Try '*.txt'.
    – Freddy
    Commented Feb 28, 2023 at 18:22
0

I would do it like this:

while read -r file; do mv $file /path/to/dir/$(echo $file | tr '/' '_'); done < <(find / -name *.txt -type f 2>/dev/null)

this will loop through all the results of the find command and move them to the desired dir.

If you want to copy them instead you can use the cp command

1
  • you're right my bad, edited
    – Noft
    Commented Feb 28, 2023 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .