AnswerBun.com

How copy and rename files found in "find" function Linux?

Unix & Linux Asked by Mirage on December 17, 2020

I have a folder named /home/user/temps which has 487 folders.
In each folder I have a file called thumb.png.

I want to copy all files named thumb.png to a separate folder and rename them based on the folder they came from.

6 Answers

Here you go:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file//thumb/}"; done;

edit:

the canonical wisdom, by the way, is that using find for this is a bad idea -- simply using shell expansion is much more reliable. Also, this assumes bash, but I figure that's a safe assumption :)

edit 2:

for clarity, I'll break it down:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file//thumb/}";
done;

details on the ${var/Pattern/Replacement} construct can be found here.

the quotes in the cp line are important to handle spaces and newlines etc. in filenames.

Correct answer by simon on December 17, 2020

You can find, copy, and rename files in oneliner command with -exec sh:

find /home/user/temps -name thumb.png 
-exec sh -c 'cp "{}" "$(basename "$(dirname "{}")")_$(basename "{}")"' ;

(The extra " are meant to deal with copying files with spaces).

Option 2 - with xargs (it can print each command before it is executed):

find /home/user/temps -name thumb.png 
| xargs -I {} --verbose sh -c 'cp "{}" "$(basename "$(dirname "{}")")_$(basename "{}")"'

sh -c cp "temps/thumb.png" "$(basename "$(dirname "temps/thumb.png")")_$(basename "temps/thumb.png")"

sh -c cp "temps/dir one/thumb.png" "$(basename "$(dirname "temps/dir one/thumb.png")")_$(basename "temps/dir one/thumb.png")"

sh -c cp "temps/dir two/thumb.png" "$(basename "$(dirname "temps/dir two/thumb.png")")_$(basename "temps/dir two/thumb.png")"

Answered by Noam Manos on December 17, 2020

Short helper code:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1////_}" 
#
mv "$1" ../tmp/"${1////_}"

let's name it 'deslash.sh' and make it executable. Call it with:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

It will fail, if a collision exists

a/b/thumb.png # and 
a_b/thumb.png 

but that's unavoidable.

Answered by user unknown on December 17, 2020

This works for arbitrarily deep subdirectories:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME////_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

The interessting part is the parameter expansion ${NAME////_}. It takes the content of NAME, and replaces every occurence of / with _.

Note: the result is dependent on the working directory and the path parameter for find. I executed the command from the parent directory of temps. Replace cp with echo to experiment.

Answered by lesmana on December 17, 2020

Try this

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

Edit

I have added quoting in case any of your dir names have white-space chars embedded in them.

Also I have changed this so it will only print out the commands to be executed. Examine the output of the script to be sure all files/path names look proper. When you're sure there are no issues with the commands that will be executed, remove the echo.

Answered by shellter on December 17, 2020

To copy you need the command cp, and to rename for linux is the same than moving the file, so you have to do it with mv command. In Linux you always have to specify the whole path, from the source, if you are in another folder, and to the destination folder, of course. I'd be something like this, for copy:

cp /source_path/file /destination_path/

or to rename or move

mv /source_path/old_file /destination_path/new_name_file

Answered by elvenbyte on December 17, 2020

Add your own answers!

Related Questions

Why is irqs_disabled() an unsafe way of disabling preemption?

2  Asked on November 29, 2020 by holmes-sherlock

   

How to debug and monitor the power management?

0  Asked on November 28, 2020 by jonas-stein

     

How do I run grep on a zsh variable?

2  Asked on November 28, 2020 by serge-vu

     

This system is currently not set up to build kernel modules

1  Asked on November 28, 2020 by henrique-de-sousa

   

unable to install anything in Dockerfile

1  Asked on November 27, 2020 by bitfreak

     

Reset cursor state without reopening terminal

1  Asked on November 27, 2020 by nordine-lotfi

 

Bash commands not found

3  Asked on November 26, 2020 by yuseferi

     

How can I install mysql on an angstrom distribution?

1  Asked on November 26, 2020 by e-lee

   

BASH_ENV being ignored in AWS Ubuntu 20.04 crontab

1  Asked on November 26, 2020 by arturomp

       

Display tasks in GNOME Shell Calendar

1  Asked on November 25, 2020 by ofperkins

 

Apache is not starting up

1  Asked on November 13, 2020 by georgi-stoyanov

       

Ask a Question

Get help from others!

© 2022 AnswerBun.com. All rights reserved. Sites we Love: PCI Database, MenuIva, UKBizDB, Menu Kuliner, Sharing RPP, SolveDir