문제
UNIX bash 쉘 (특히 Mac OS X Leopard)에서 특정 확장자를 가진 모든 파일을 폴더 계층 (하위 디렉토리 포함)에서 동일한 대상 폴더 (하위 폴더없이)로 복사하는 가장 간단한 방법은 무엇입니까?
분명히 소스 계층 구조에 중복 항목이있는 문제가 있습니다.덮어 써도 괜찮습니다.
예 : 다음 계층 구조의 모든 .txt 파일을 복사해야합니다. 라코 디스
'dest'라는 폴더로 이동하여 다음을 가져옵니다. 라코 디스
해결책
bash에서 : 라코 디스
find
는 대소 문자를 구분하지 않고 와일드 카드 /foo
와 일치하는 *.txt
경로 아래의 모든 파일을 찾습니다 (즉, -iname
가 의미하는 바입니다).각 파일에 대해 find
는 cp {} /dest/
대신 발견 된 파일을 사용하여 {}
를 실행합니다.
다른 팁
The only problem with Magnus' solution is that it forks off a new "cp" process for every file, which is not terribly efficient especially if there is a large number of files.
On Linux (or other systems with GNU coreutils) you can do:
find . -name "*.xml" -print0 | xargs -0 echo cp -t a
(The -0 allows it to work when your filenames have weird characters -- like spaces -- in them.)
Unfortunately I think Macs come with BSD-style tools. Anyone know a "standard" equivalent to the "-t" switch?
The answers above don't allow for name collisions as the asker didn't mind files being over-written.
I do mind files being over-written so came up with a different approach. Replacing each / in the path with - keep the hierarchy in the names, and puts all the files in one flat folder.
We use find to get the list of all files, then awk to create a mv command with the original filename and the modified filename then pass those to bash to be executed.
find ./from -type f | awk '{ str=$0; sub(/\.\//, "", str); gsub(/\//, "-", str); print "mv " $0 " ./to/" str }' | bash
where ./from and ./to are directories to mv from and to.
If you really want to run just one command, why not cons one up and run it? Like so:
$ find /foo -name '*.txt' | xargs echo | sed -e 's/^/cp /' -e 's|$| /dest|' | bash -sx
But that won't matter too much performance-wise unless you do this a lot or have a ton of files. Be careful of name collusions, however. I noticed in testing that GNU cp at least warns of collisions:
cp: will not overwrite just-created `/dest/tubguide.tex' with `./texmf/tex/plain/tugboat/tubguide.tex'
I think the cleanest is:
$ find /foo -name '*.txt' | xargs -i cp {} /dest
Less syntax to remember than the -exec option.
As far as the man page for cp on a FreeBSD box goes, there's no need for a -t switch. cp will assume the last argument on the command line to be the target directory if more than two names are passed.