17

I want to backup only my FLAC music folders. FLAC files could be nested like that inside the folders:

AlbumName/
├── Files/
│   ├── someSong01.flac
│   ├── someSong02.flac
├── Covers/
│   ├── someCover01.jpg
│   └── someCover02.jpg

How do I copy and move all AlbumName's folders with their corresponding structure and content that contain somewhere inside at least one FLAC file (I'll assume this is enough to say: the music is in FLAC format)

EDIT: FLAC files could be nested; so I can have:

AlbumName2/
├── someSong01.flac
├── someSong02.flac
├── Covers/
│   ├── someCover01.jpg
|   └── someCover02.jpg

And I want to copy those folders with all their contents, not only FLAC files, and paste to another directory.

So if I have as well

AlbumName3/
├── someSong01.mp3
├── someSong02.mp3
├── Covers/
│   ├── someCover01.jpg
|   └── someHiddenSong.flac

and

AlbumName4/
├── Files/
│   ├── someSong01.mp3
│   ├── someSong02.mp3
├── Covers/
│   ├── someCover01.jpg
│   └── someCover02.jpg

I want to cp recursively to another directory AlbumName, AlbumName2 and AlbumName3 but not AlbumName4

EDIT: None of the answers were really doing what I want, so I ended up using something like that:

 find -mindepth 2 -name '*.flac' -exec dirname {} \; | awk -F "/" '{print $2}' | sort -u | while read -r dirname; do cp -r "$dirname" "backup/"; done

basically I list all flac files, I retrieve the root folder using awk, I delete the duplicates and I do what I want

3
  • backup to where, what is your destination? Dec 21, 2017 at 8:25
  • Do only flac files need to be copied or whole folders that have at least one flac file?
    – nobody
    Dec 21, 2017 at 9:14
  • @nobody folders: "How do I copy and move all AlbumName's folders with their corresponding structure and content that contain somewhere inside at least one FLAC file"
    – terdon
    Dec 21, 2017 at 10:21

5 Answers 5

19

An option is to use rsync, which copies only flac files and preserves directory structure:

rsync -avzm --include=*/ --include=*.flac --exclude=* albums/ backup/
  • a archive
  • v verbose
  • z compress during transfer (may not be useful copying on the same computer)
  • m prune empty dirs
  • first include includes all directories
  • second include includes flac files
  • the last exclude excludes all other files
3
  • Really? I understand, he wants to preserve directory structure. He says: "How do I copy and move all AlbumName's folders with their corresponding structure and content...".
    – nobody
    Dec 21, 2017 at 9:09
  • 2
    Oh, I see. I am not sure. Do only flac files need to be copied or whole folders that have at least one flac file?
    – nobody
    Dec 21, 2017 at 9:13
  • The question is edited and now it explains in more detail, what fricadelle wants. Taken into account that all content shall be copied, if there is a flac file, my answer is wrong as it copies only flac files. However it may still be useful for some other purpose.
    – nobody
    Dec 21, 2017 at 13:29
9

hi my friend you can use

mkdir newdirectory
cp -r --parents */*.flac newdirectory/
4
  • 2
    Nice never used --parents before! Dec 21, 2017 at 8:35
  • 4
    Please explain this */*.flac! Will cp -r --parents AlbumName/ newdirectory/ not suffice? Dec 21, 2017 at 8:37
  • 3
    From the question, it sounds like the flacs may or may not be in nested directories, so I'd recommend to enable globstar (shopt -s globstar), then use **/*.flac for the glob. The double-star will match zero or more directories.
    – wjandrea
    Dec 21, 2017 at 8:39
  • you are exactly right wjandrea, let me edit my question so everybody understands
    – fricadelle
    Dec 21, 2017 at 9:55
5

Nice answers

I want to add one more way, you can also use a combination of find and cpio

find . -name "*.flac" -print0|cpio --null -pdm destination/

Explanation:

GNU find searches the directory tree rooted at each given file name by evaluating the given expression from left to right, according to the rules of precedence (see Operators), until the outcome is known (the left-hand side is false for AND operations, true for OR), at which point find moves on to the next file name.

GNU cpio is a tool for creating and extracting archives, or copying files from one place to another. It handles a number of cpio formats as well as reading and writing tar files.

There are 3 cpio modes:

  • Copy-out mode: In copy-out mode, cpio copies files into an archive. It reads a list of filenames, one per line, on the standard input, and writes the archive onto the standard output.

  • Copy-in mode: In copy-in mode, cpio copies files out of an archive or lists the archive contents. It reads the archive from the standard input.

  • Copy-pass mode: In copy-pass mode, cpio copies files from one directory tree to another, combining the copy-out and copy-in steps without actually using an archive. It reads the list of files to copy from the standard input; the directory into which it will copy them is given as a non-option argument.

Here, we are using Copy-pass mode.

  • Options Used in above command:

find:

  • -name -> filename or use regex instead of writing full-name

cpio:

  • '-m, --preserve-modification-time' Retain previous file modification times when creating files.
  • '-p,--pass-through' Run in copy-pass mode. see ``Copy-pass mode``.
  • '-d, --make-directories' Create leading directories where needed.'
  • --quiet' Do not print the number of blocks copied.`

New options are the "-print0" available with GNU find, combined with the "--null" option of cpio. These two options act together to send file names between find and cpio, even if special characters are embedded in the file names.

One can also use rsync or write a shell script to find and copy files with the directory structure.

For Rsync explanation, Please have a look at above answers.

2
  • 2
    You could improve your answer by including explanations of the commands and the options you suggest. - From Review
    – J. Starnes
    Dec 21, 2017 at 9:13
  • @dessert yeah, right. Thank you, for your perfect suggestion.
    – bsdboy
    Dec 21, 2017 at 9:59
4

Answer 1: You can also use find command for same.

mkdir newDir && find AlbumName/ -iname "*.flac" -exec cp --parents "{}" newDir/ \;

Explaination:

mkdir creates new directory. find command finds *.flac files located in AlbumName folder. exec command executes cp command to each of the filename that find has returned.

Answer 2: You can also use find command with xargs as well

mkdir newDir && find AlbumName/ -iname "*.flac" | xargs -I{} cp --parents {} newDir/

More information: find, xargs

5
  • 1
    find | xargs will break on filenames with spaces, rather use find -print0 | xargs -0 instead.
    – dessert
    Dec 21, 2017 at 9:06
  • i tried with 1 2.flac file which has space in filename. Can you please let me know the file name on which find | xargs fails ? Dec 21, 2017 at 9:15
  • see e.g. here
    – dessert
    Dec 21, 2017 at 9:25
  • I dont know but I am able to copy file with long name which has space contained in it without use of find -print0 | xargs -0 Dec 21, 2017 at 9:32
  • Try touch "a space" && find . | xargs ls.
    – dessert
    Dec 21, 2017 at 9:34
0

Just had the to solve the same problem for my music library and solved it using the following adapted script. I did not fully engineer it with i.e. variables, as I only intend to use it once :).

The script moves every directory containing flac files including all other files and subdirectories to a new location using rsync. rsync allows you to resume the script if it stops during the process.

My library structure:

library
|-artist
  |- album 1 (mp3)
  |- album 2 (flac)

New library structure:

library
|-artist
  |- album 1 (mp3)

library-lossless
|-artist
  |- album 2 (flac)

(1) start the following shell script in the SOURCE destination (replace TARGET with the respective directory of your choice - I just used the absolute path)

row 1: find all directories containing flac files and pipe (|) that into sort
row 2: remove duplicates with sort and pipe that list into the do loop
row 3: for each directory do
row 4: show the directory in process
row 5: rsync to the target directory plus remove source and preserve structure (-R) in target location
row 6: remove empty directory (as rsync only removes files)

find . -type f -name \*.flac -printf "%h\n" | 
sort -u | 
while read -r dirname; do
    echo $dirname
    rsync -azvm -R --remove-source-files "${dirname}" TARGET
    find "${dirname}" -type d -delete
done

(2) after successfully executing the script in (1) you may execute the following command in the source directory

find . -depth -type d -empty -delete

This command deletes all empty directories not deleted within the script. I.e. "Artist" directories, where all subfolders/albums included flac files.

You must log in to answer this question.

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