Copy multiple files from filename X to filename Y?

cp
23,856

Solution 1

A generic approach is to define a shell function that prints a range of filenames. A simple version of this function will list all the files between two filenames inclusive in the current directory:

range()
{
    ls | sed -n "/^$1\$/,/^$2\$/p"
}

This uses a sed range saying to print out anything between the two given strings ($1 and $2).

You can then use this function in your cp(1) command:

cp $(range asps.cfg acpi.txt) /destination/path

This will fail if you have filenames with spaces in them. For that, you need to get a little more complicated:

range asps.cfg acpi.txt | xargs -d '\n' -I {} cp {} /destination/path

That will fail if your filenames have newlines (\n) in them. That is very unlikely, so fixing that is left as an exercise for the reader.

You could roll that together into another shell function:

cprange()
{
    [ $# -eq 3 ] || { echo "usage: cprange start end dir" >&2; return 1;}
    range "$1" "$2" | xargs -d '\n' -I {} cp {} "$3"
}

and use it like:

cprange filenameX filenameY destination

Remember, range only works for filenames in the current directory. You can expand on that in a number of ways (additional directory parameter to range, extract a path from arguments to range using dirname, etc) but I'll leave that up to you based on your requirements. Please ask if you want more details here.

Solution 2

Zsh has an easy way to select a range of files out of the result of a glob (a glob is a wildcard match). On the plus side, the command is very short to write. On the minus site, you'll have to figure out the ordinals of the files you want to write. For example, the following command copies the 21st, 22nd, …, 40th file with a .jpg extension in the current directory, with the files enumerated in alphabetical order:

cp *.jpg([21,40]) destination/

Zsh has an option that may or may not be helpful to you: under setopt numeric_glob_sort, foo9bar.jpg will be sorted before foo10bar.jpg. You can also choose a different sorting order in the glob qualifiers, e.g. cp *.jpg(om[21,40]) destination/ to pick the 21st to 40th most recent files (use a capital O to sort in the opposite order). See glob qualifiers in the manual for more information.

Under any shell, you could write a loop that iterates over the files, starts copying at the first file you want to write, and stops after the last file. Warning, untested.

in_range=
for x in *.jpg; do
  if [ "$x" = "first-file.jpg" ]; then in_range=1; fi
  if [ -n "$in_range" ]; then cp "$x" destination/; fi
  if [ "$x" = "last-file.jpg" ]; then break; fi
done
Share:
23,856

Related videos on Youtube

Tiax
Author by

Tiax

Updated on September 18, 2022

Comments

  • Tiax
    Tiax almost 2 years

    What I want to do is to copy files within a lexicographic range.

    Example of files:

    -rw-r--r--   1 root root   15276 Oct  5  2004 a2ps.cfg
    -rw-r--r--   1 root root    2562 Oct  5  2004 a2ps-site.cfg
    -rw-r--r--   4 root root    4096 Feb  2  2007 acpi.txt
    -rw-r--r--   1 root root      48 Feb  8  2008 adjtime.jpg
    -rw-r--r--   4 root root    4096 Feb  2  2007 alchemist.jpg
    

    Example of use:

    • Copy the 3 files from asps.cfg to acpi.txt
    • Copy the 3 files from a2ps-site.cfg to adjtime.jpg
    • Copy the 4 files from a2ps-site.cfg to alchemist.jpg

    So is there any way to copy a range of files (from filename X to filename Y) into a directory?

    Like: cp filenameX ... filenameY destination/

    • Admin
      Admin about 13 years
      It's getting late here ... but it's not clear how or why you would copy 'cfg' files to 'jpg', and why you say there are 'ranges'. Also they appear to be owned by root. Will you do this copying as root?
    • Admin
      Admin about 13 years
      I guess he means copying all files from asps.cfg to acpi.txt to some destination folder, or that is at least how I interpreted it.
    • Admin
      Admin about 13 years
      The files are just exemples, I'm gonna copy lots of images.
    • Admin
      Admin about 13 years
      I think it would be more helpful if your example was your actual use case. As it stands, it is pretty difficult to determine what you need to do.
    • Admin
      Admin about 13 years
      My actual use case is about 200 images so that would be to long.. I used 5 files case it is enough to show what Im after. What I need to do is the examples of use in the question. If you don't understand the question you can't answer it ;)
    • Admin
      Admin about 13 years
      My point was not to list every single image but to ensure that these were actually representative of the type of file names you will be working with. camh's answer, while clever, will break on most whitespace and a variety of other characters.
    • Admin
      Admin about 13 years
      @Tiax: Your question was formulated in a very confusing way, because “copy from X to Y” usually means that Y is the destination. I hope I've reformulated it correctly.
  • Admin
    Admin about 13 years
    Since it's gonna be lots of images that way is to complicated..
  • Tiax
    Tiax about 13 years
    How do I define the function range()? I tried creating a file named range.sh with the funtion in it then running ./range.sh but then when I try using it, it says "-sh: range: command not found"
  • Steven D
    Steven D about 13 years
    You need to source the file rather than run it so that the function is in your current bash environment. Like: source range.sh
  • camh
    camh about 13 years
    If it's a function that you may use a lot, put it in your .bashrc. Otherwise you can just create a shell script on your path and leave out the function wrapping.
  • tcoolspy
    tcoolspy about 13 years
    If the object is just to batch them, there is a MUCH easier way! ls | xargs -iX -n20 cp X target_folder/ would run cp on files in batches of 20 until they were all done.
  • Can Burak Çilingir
    Can Burak Çilingir about 13 years
    The difference is, your version, target folder is same for all batches.