Shell script to copy and prepend folder name to files from multiple subdirectories
This is a bit tedious but will do:
#!/bin/bash
parent=/parent
newfolder=/newfolder
mkdir "$newfolder"
for folder in "$parent"/*; do
if [[ -d "$folder" ]]; then
foldername="${folder##*/}"
for file in "$parent"/"$foldername"/*; do
filename="${file##*/}"
newfilename="$foldername"_"$filename"
cp "$file" "$newfolder"/"$newfilename"
done
fi
done
Put the parent path to parent
variable and newfolder path to newfolder
variable.
Shell Script Copy All Files and Subdirectories - Folder Names With Spaces
Try:
cp -r "/shrdata/Legal/test location/test folder"/* "/shrdata/Legal/open access/"
For the *
to work properly, it must be outside of quotes.
Example
Suppose that we have a test folder
with two files:
$ ls -1 test\ folder/
file1
file2
Now, let's try putting the *
in quotes:
$ echo "test folder/*"
test folder/*
Because the *
is in quotes, it is not expanded into a list of filenames. Instead, it is merely treated as a literal character. Consequently, if we try to copy files this way, we will get a file-not-found error because no file is named *
:
$ cp "test folder/*" target
cp: cannot stat ‘test folder/*’: No such file or directory
If we place the *
outside of quotes, then pathname expansion will be performed:
$ echo "test folder"/*
test folder/file1 test folder/file2
This means that this form will work properly when used with cp
.
Copy all files in folder to another folder prepending a . to the file name and rename it back to original file name
Let's suppose we have two directories as follows:
$ ls -a foo*
foo1:
. .. file1 file2 file3 'file 4'
foo2:
. ..
If we execute next command:
$ for file in foo1/* ; do base=$(basename "$file"); cp "foo1/$base" "foo2/.$base"; mv "foo2/.$base" "foo2/$base"; done
We will get at the end:
$ ls -a foo*
foo1:
. .. file1 file2 file3 'file 4'
foo2:
. .. file1 file2 file3 'file 4'
I think this is what you wanted.
Moreover, the file names with spaces inside will be correctly handled.
Copy multiple file from multiple directories with new filename
Note that above $file
is set only by the for file in ... ; do ... ;done
loop, i.e. in your xargs
cmdline you were just using the last leftover value from the loop.
Some things to consider:
need to process each file separately => use
xargs -l1
(process each 1 line).need to separate
DIR/FILENAME
as the needed command is something like 'cp $DIR/$FILENAME $DIR/prefix-01-$FILENAME' (and prefix-02 also), usefind ... -printf "%h %f\n"
for thisfor each line, need to do couple things (prefix-01,02) => use a scriptlet via
sh -c '<scriptlet>'
better skip
prefix-0?-*.jpg
files fromfind
, to be able to re-run it without "accumulating" copies
A possible implementation would be:
find . -type f \( -iname "*.jpg" ! -iname "special-*.jpg" ! -name "prefix-0?-*.jpg" \) -printf "%h %f\n" | \
xargs -l1 sh -c 'cp -v "$1/$2" "$1/prefix-01-$2"; cp -v "$1/$2" "$1/prefix-02-$2"' --
As xargs
runs sh -c '<scriptlet>' -- DIR FILE
for each line, the scriptlet will properly evaluate $1
and $2
respectively.
--jjo
PS: directory separator in Unix-like systems is /
:)
[Update: fixed to use %f
instead of %P
, as per comments below]
Copying files in multiple subdirectories in the Linux command line
Let the shell help you out:
find . -name '*.in' | while read old; do
new=${old%.in}.out # strips the .in and adds .out
cp "$old" "$new"
done
I just took the find command you said works and let bash read its output one filename at a time. So the bash while loop gets the filenames one at a time, does a little substitution, and a straight copy. Nice and easy (but not tested!).
Prefix every file in subdirectories with the folder name
You need to use Get-ChildItem
(alias dir
) and specify parameters Recurse
and File
at least, so your code will traverse subdirectories and rename files only (not also folder objects)
$rootFolder = 'D:\Test' # the folder where the subfolders storing the PDF files are
(Get-ChildItem -Path $rootFolder -Filter '*.pdf' -File -Recurse) | Rename-Item -NewName {
'{0}_{1}' -f $_.Directory.Name, $_.Name
}
If you run the above several times, then each time the pdf files get their name prefixed with the directory name, so you'll end up with files like foo_foo_foo_file1.pdf
.
To prevent that from happening, you can add a Where-Object
clause like:
$rootFolder = 'D:\Test'
(Get-ChildItem -Path $rootFolder -Filter '*.pdf' -File -Recurse) |
Where-Object { $_.Name -notmatch "^$($_.Directory.Name)_" } |
Rename-Item -NewName { '{0}_{1}' -f $_.Directory.Name, $_.Name }
Note that the brackets around the Get-ChildItem cmdlet are needed to make sure it does not 'pick up' any file you have renamed earlier in the pipe
Related Topics
Udev - Run Program on Usb Flash Drive Insert
How to Run Elasticsearch 2.1.1 as Root User in Linux MAChine
How to Check Whether the Processor Cache Has Been Flushed Recently
Installing Qt on Linux, Cannot Find -Lgl
Set Static Ip If Not Obtained from Dhcp (Script)
Is a Core Dump Executable by Itself
Sed Command:How to Replace If Exists Else Just Insert
Writing Log Data to Syslog Using Log4J
Assigning Output of a Command to a Variable(Bash)
Putting Two Consecutive Lines into One Line with Perl/Awk
Using the Linux Sysfs_Notify Call
Search Ms Word Files in a Directory for Specific Content in Linux
Run Silverlight with Apache Server (Under Linux)
How to Copy File to Stopped Docker Container
Get a Nanosecond-Precise Atime, Mtime, Ctime Fields for File (Stat)
Where Do You Download Linux Source Code