0

Let's say, under this directory: /home/data/

There are 100 folders, the name of these folders are 24538_7#1, 24538_7#2, 24538_7#3 ... to 24538_7#384.

In each folder, there are many files and folders.

The names of the desired file in each folder is Aligned.out.sam The desired folder for renamed files is /home/SAM

How can I copy all these files to the new folder(/home/SAM) and rename them properly as 24538_7#1.sam, 24538_7#2.sam, 24538_7#3.sam ......?

I tried doing it by the command below but it didn't work:

mv /home/data/*/Aligned.out.sam /home/SAM/*.sam

  • @bertieb I've included my effort in the question. Please have a look. – Akhil Verma Jun 13 '18 at 16:50
  • 1
    You mustn't use *.sam in the target. If there are no files in the target directory, a file called *.sam will be created there and each source file will overwrite it in turn. With an mv command this means that you will lose all your files apart from the last. If a .sam file exists in the target directory, each source file will overwrite it, as before. If multiple .sam files exist in the target directory, then all the source files and all the target files except the last will overwrite the last, so you will also lose existing .sam files in the target, apart from the second last. – AFH Jun 13 '18 at 17:13
  • The loop approach below is what you should use. The wildcard * won't work in the second invocation in that command, as bash has no idea you want each name on the left side to be the same as on the right side. Using a variable in a loop allows you to say "for each directory, copy the file and rename it to match the originating directory". – zymhan Jun 13 '18 at 17:14
  • @AFH, I tried creating 384 sam files and then using the mv command too, but it didn't work. – Akhil Verma Jun 13 '18 at 17:16
  • 1
    Eugen Rieck has already given you an answer: @zymhan doesn't need to duplicate it. – AFH Jun 13 '18 at 17:23
1

Something along the lines of

for sam in */Aligned.out.sam; do \
  name=$(basename $(dirname "$sam")) \
  cp "$sam" "/home/SAM/$name.sam" \
done

might do the trick

  • I would advocate the use of parameter parsing: name=${sam%/*}; name=${name##*/}. Your answer requires two nested subshells and two external programs. – AFH Jun 13 '18 at 17:27
  • @AFH Both basename and dirname are bash built-ins, not external programs. In addition to that bash hasn't been spawning a full subshell for this kind of construct for many versions. I also value the much better readability of the constructs much higher, then the few CPU cycles they might or might not cost. This is why I rejected your edit, but you are welcome to provide them in a second answer. – Eugen Rieck Jun 13 '18 at 18:18
  • They are external programs on Ununtu bash, but I hadn't realised that $() doesn't invoke a subshell. Thanks for correcting me. – AFH Jun 13 '18 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.