0

I am having the following problem in linux:

I need to find specific files from a directory and copy those files (if they exist) into another directory

this is the command (i need to find specific text files starting with the word log) and only take the last 10 recent ones; the command works

find /mydir -type f -name 'log*.txt' | tail -n 10

there is no recursion involved, i can just find the files and copy them

however i am having a problem combining this with a copy command ; i tried this:

find /mydir -type f -name 'log*.txt' | tail -n 10 -exec cp --parents \{\} /tmp/mydir \;

it can't execute -exec , something is wrong here.

thanks

3
  • 1
    --exec belongs to the find command, not to tail. You could pipe the output of tail to xargs, see man7.org/linux/man-pages/man1/xargs.1.html, specifically option -I replace-str.
    – Bodo
    May 20, 2022 at 12:32
  • Note that find outputs filenames in whatever order it finds them in the directory. This probably isn't going to be sorted by time. If you need to sort find's output by time, then (with GNU find, sort, cut, tail, and cp): find /mydir -type f -name 'log*.txt' -printf '%C@\t%p\0' | sort -z -n -k1,1 | cut -z -f2 | tail -z -n 10 | xargs -0r cp --parents -t /tmp/mydir/. The printf prints the mod time before the filename, the output is sorted, the timestamp is cut, then piped into tail and finally into xargs which runs cp with the -t option. The entire pipeline uses NUL to separate filenames.
    – cas
    May 21, 2022 at 2:51
  • 1
    GNU cp's -t option allows you to specify the target directory before the filename. This is especially useful for avoiding having to complicate the command line (e.g. with exact placement of {} in find or xargs' -I option, which often can't be made to do what you hope it can do) to ensure the filenames come before the target dir. BTW, the cut -z -f2 above should be cut -z -f2- (just in case any filenames have tabs in them).
    – cas
    May 21, 2022 at 2:56

2 Answers 2

0

I would use xargs to copy all files.

You can pipe the output to xargs which executes cp to all passed arguments. The Wikipedia article describes xargs better than I could do and you could look into the manpage of Linux.

A call that does what you want could be:

find /mydir -type f -name 'log*.txt' | tail -n 10 | xargs -I % cp % /tmp/mydir/

The -I flag followed by % cp % means that all passed arguments will concatenated to the last %

1
  • thank you very much
    – Josh.h
    May 20, 2022 at 12:58
-3

A more use-case solution using variables in a script:

#!/bin/bash
path1=/mydir
path2=/tmp/mydir
filetype=log*.txt
find_file="$(find $path1 -type f -name "$filetype" -printf "%f\n" | tail -n 10)"
for f in $find_file
do
    cp $f $path2
done

I spent nearly 2 full days rewriting my cp command for my use case, trying to implement find, grep, awk, xargs, loops, etc before simply trying to cp the variables. Lo and behold, it worked. My main breaking point was that my find command substitution was storing ALL of the file names into $find_file and trying to cp something that didn't actually exist, which it is supposed to do, but still frustrating.

Hopefully this helps someone!

4
  • Well, let’s see. (1) You added -mtime -1 out of thin air, (2) you changed -name 'log*.txt' to -name "*$filetype*", which expands to -name "*log*" (i.e., it does something different), (3) you replaced the default -print with -printf "%f\n", which can cause problems if any filename(s) begin with ‘-’ and is just plain wrong if find finds any files in subdirectories, and (4) you changed /tmp/mydir to /path/to/files/ (again, out of thin air).  And (5) you describe a problem that you encountered, but don’t say how you resolved it.  … (Cont’d) Mar 1 at 23:10
  • (Cont’d) …  And then, (6) you reference $f and $path without quoting them.  What value have you added over the accepted answer? Mar 1 at 23:10
  • (1) added/fixed $path1. (2) added $path2. (3) fixed $filetype. (4) fixed $find_file. (5) fixed for loop (6) added shebang. Thanks, @G-ManSays'ReinstateMonica'. I utilize the -printf "%f\n" to remove the path and only save file names. What is the purpose of quoting $f and $path? unquoted works for me in production as expected.
    – fischdix
    Mar 6 at 1:27
  • I guess no files/directories have spaces in them in your environment?
    – tink
    Mar 6 at 8:26

You must log in to answer this question.

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