1

There are multiple directories which contain a file with the same name:

direct_afaap/file.txt
direct_fgrdw/file.txt
direct_sardf/file.txt
...

Now I want to extract them to another directory, direct_new and with a different file name such as:

[mylinux~ ]$ ls direct_new/
file_1.txt  file_2.txt  file_3.txt

How can I do this?

BTW, if I want to put part of the name in original directory into the file name such as:

[mylinux~ ]$ ls direct_new/
file_afaap.txt  file_fgrdw.txt  file_sardf.txt

What can I do?

codeforester
  • 39,467
  • 16
  • 112
  • 140
spring cc
  • 937
  • 1
  • 10
  • 19

4 Answers4

1
while read -r line; do 
   suffix=$(sed 's/^.*_\(.*\)\/.*$/\1/' <<<$line)
   newfile=$(sed 's/\.txt/$suffix\.txt/' <<<$line)
   cp "$line" "~/direct_new/$newfile"
done <file_list.txt

where file_list is a list of your files.

Michael
  • 5,095
  • 2
  • 13
  • 35
1

This little BaSH script will do it both ways:

#!/bin/sh
#

# counter
i=0

# put your new directory here
# can't be similar to dir_*, otherwise bash will
# expand it too
mkdir newdir

for file in `ls dir_*/*`; do
    # gets only the name of the file, without directory
    fname=`basename $file`
    # gets just the file name, without extension
    name=${fname%.*}
    # gets just the extention
    ext=${fname#*.}

    # get the directory name
    dir=`dirname $file`
    # get the directory suffix
    suffix=${dir#*_}

    # rename the file using counter
    fname_counter="${name}_$((i=$i+1)).$ext"

    # rename the file using dir suffic
    fname_suffix="${name}_$suffix.$ext"

    # copy files using both methods, you pick yours
    cp $file "newdir/$fname_counter"
    cp $file "newdir/$fname_suffix"
done

And the output:

$ ls -R
cp.sh*
dir_asdf/
dir_ljklj/
dir_qwvas/
newdir/
out

./dir_asdf:
file.txt

./dir_ljklj:
file.txt

./dir_qwvas:
file.txt

./newdir:
file_1.txt
file_2.txt
file_3.txt
file_asdf.txt
file_ljklj.txt
file_qwvas.txt
Enzo Ferber
  • 3,029
  • 1
  • 14
  • 24
  • You don't need to use `basename` and `dirname` which is expensive. Also, parsing `ls` output is not a good idea, just globbing would work well. Also, no need to extract suffix since it is fixed (`.txt`). Please see my [answer](https://stackoverflow.com/a/44479825/6862601). – codeforester Jun 11 '17 at 02:24
0

You can achieve this with Bash parameter expansion:

dest_dir=direct_new

# dir based naming
for file in direct_*/file.txt; do
  [[ -f "$file" ]] || continue # skip if not a regular file
  dir="${file%/*}"             # get the dir name from path
  cp "$file" "$dest_dir/file_${dir#*direct_}.txt"
done

# count based naming
counter=0
for file in direct_*/file.txt; do
  [[ -f "$file" ]] || continue # skip if not a regular file
  cp "$file" "$dest_dir/file_$((++counter)).txt"
done
  • dir="${file%/*}" removes all characters starting from /, basically, giving us the dirname
  • ${dir#*direct_} removes the direct_ prefix from dirname
  • ((++counter)) uses Bash arithmetic expression to pre-increment the counter

See also:

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
codeforester
  • 39,467
  • 16
  • 112
  • 140
-1

It may not be quite what you want, but it will do the job. Use cp --backup=numbered <source_file> <destination_directory:

$ find . -name test.sh
./ansible/test/integration/roles/test_command_shell/files/test.sh
./ansible/test/integration/roles/test_script/files/test.sh
./Documents/CGI/Code/ec-scripts/work/bin/test.sh
./Documents/CGI/Code/ec-scripts/trunk/bin/test.sh
./Test/test.sh
./bin/test.sh
./test.sh

$ mkdir BACKUPS

$ find . -name test.sh -exec cp --backup=numbered {} BACKUPS \;
cp: './BACKUPS/test.sh' and 'BACKUPS/test.sh' are the same file

$ ls -l BACKUPS
total 28
-rwxrwxr-x. 1 jack jack 121 Jun  9 10:29 test.sh
-rwxrwxr-x. 1 jack jack  34 Jun  9 10:29 test.sh.~1~
-rwxrwxr-x. 1 jack jack  34 Jun  9 10:29 test.sh.~2~
-rwxrwxr-x. 1 jack jack 388 Jun  9 10:29 test.sh.~3~
-rwxrwxr-x. 1 jack jack 388 Jun  9 10:29 test.sh.~4~
-rwxrwxr-x. 1 jack jack  20 Jun  9 10:29 test.sh.~5~
-rwxrwxr-x. 1 jack jack 157 Jun  9 10:29 test.sh.~6~

If you really want to put part of the folder name in, you have to decide exactly what part you want. You could, of course, just replace the directory separator character with some other character, and put the whole path into the filename.

Jack
  • 5,801
  • 1
  • 15
  • 20