copy files while preserving directory structure in mac - macos

How to copy files from one directory to another while preserving the directory structure in mac?
I found that you can use cp --parents in ubuntu but unfortunately that doesn't work in mac.

I ended up using rsync -R to solve this.

On OS X you can use ditto <source> <destination>
See here:
http://osxdaily.com/2014/06/11/use-ditto-copy-files-directories-mac-command-line/

I'm tired of writing this manually, so I'm going to provide a non rsync way for future reference.
#!/bin/bash
cpParents() {
src=(${*: 1:-1})
dest=${*: -1:1}
for filename in $src; do
[ -e "$filename" ] || continue
dirPath=$(dirname "${filename}")
mkdir -p $dest/$dirPath
cp $filename $dest/$dirPath
done
}

Related

When extracting an RPM on MacOs using a bash script, how come I can't see the files?

I have the following executable bash script
#!/usr/bin/env bash
function testRpm(){
local rpm=$1
local tempDir=$(mktemp -d)
pushd $tempDir #>/dev/null
rpm2cpio $rpm | cpio -idmuv
find store -name "*.jar"
}
testRpm $1
It seems pretty straight forward to me, extract the RPM, show the files. The problem is when I run it, the find doesn't show the files, it shows the directories though. If I manually enter the commands it works great.
eg.
bash -x ./test.sh myrpm.rpm
+ testRpm myrpm.rpm
+ local rpm=myrpm.rpm
++ mktemp -d
+ local tempDir=/var/folders/z4/7cl6z4_x5vq1dllx8l6vf73r0000gn/T/tmp.YWdEnKUG
+ pushd /var/folders/z4/7cl6z4_x5vq1dllx8l6vf73r0000gn/T/tmp.YWdEnKUG
/var/folders/z4/7cl6z4_x5vq1dllx8l6vf73r0000gn/T/tmp.YWdEnKUG
~/IdeaProjects
+ rpm2cpio myrpm.rpm
+ cpio -idmuv
./store/tmp/myfile1
./store/tmp/myfile2
33279 blocks
+ find store
store
store/tmp
The above script appears to work perfectly on Redhat, but not macos. If anyone has any suggestions, tips or solutions, I'd appreciate it.
What may be happening is that when you pushd, you're losing access to the RPM file, e.g. when you're in /home/me, "foo.rpm" refers to /home/me/foo.rpm but when you change directory to /tmp, "foo.rpm" now refers to /tmp/foo.rpm.
Solve this by using the absolute path to the RPM when extracting using realpath:
#!/usr/bin/env bash
function testRpm(){
local rpm=$(realpath -- "$1")
local tempDir=$(mktemp -d)
pushd $tempDir #>/dev/null
rpm2cpio "$rpm" | cpio -idmuv
find store -name "*.jar"
}
testRpm "$1"

Checking A Folder For Logs Files

Hello and thank you for for the help in advanced. I am trying to accomplish a simple check to see if a folder contains any files in end in .log. And if it does contain any file ending in a .log, simply copy it to another folder. I did try something like
if [ -f /path/to/log/*.log ]; then cp -a /path/to/log /path/to/backup/folder; fi
But that does not give me anything clean enough to work with.
Thanks so much
You could use a bash array:
shopt -s nullglob # Expand to the empty string if no files are found
logfiles=( /path/to/log/*.log )
cp -a "${logfiles[#]}" /path/to/backup/
Or a POSIXLY_STRICT approach:
cpIfExists() {
if [ -f "$1" ]; then
cp "$#"
fi
}
cpIfExists /path/to/log/*.log /path/to/backup/
You don't need to check first, just copy the files:
cp /path/to/log/*.log /path/to/backup/folder
Not near anything to test that this works for sure, but it should:
for log in `ls /path/to/log | grep .log`; do
cp /path/to/log/$log /path/to/backup/folder/
done

Bash shell: how to add a name

I am trying to rename some zip files in bash with an _orig but I seem to be missing something. Any suggestions??
My goal:
move files to an orig directory
rename original files with a "_orig" in the name
The code Ive tried to write:
mv -v $PICKUP/*.zip $ORIGINALS
for origfile in $(ls $ORIGINALS/*.zip);do
echo "Adding _orig to zip file"
echo
added=$(basename $origfile '_orig').zip
mv -v $ORIGINALS/$origfile.zip $ORIGINALS/$added.zip
done
Sorry still kinda new at this.
Using (p)rename :
cd <ZIP DIR>
mkdir -p orig
rename 's#(.*?)\.zip#orig/$1_orig.zip#' *.zip
rename is http://search.cpan.org/~pederst/rename/ (default on many distros)
Thanks to never use
for i in $(ls $ORIGINALS/*.zip);do
but use globs instead :
for i in $ORIGINALS/*.zip;do
See http://porkmail.org/era/unix/award.html#ls.
I know you've got a solution already, but just for posterity, this simplified version of your own shell script should also work for the case you seem to be describing:
mkdir -p "$ORIGINALS"
for file in "$PICKUP"/*.zip; do
mv -v "$file" "$ORIGINALS/${file%.zip}_orig.zip"
done
This makes use of "Parameter Expansion" in bash (you can look that up in bash's man page). The initial mkdir -p simply insures that the target directory exists. The quotes around $PICKUP and $ORIGINALS are intended to make it safe to include special characters like spaces and newlines in the directory names.
While prename is a powerful solution to many problems, it's certainly not the only hammer in the toolbox.

bash - For every file in a directory, copy it into another directory, only if it doesn't exists there already

Thank you very much in advance for helping!
I have a directory with some html files
$ ls template/content/html
devel.html
idex.html
devel_iphone.html
devel_ipad.html
I'd like to write a bash function to copy every file in that folder into a new location (introduction/files/), ONLY if a file with the same name doesn't exist already there.
This is what I have so far:
orig_html="template/content/html";
dest_html="introduction/files/";
function add_html {
for f in $orig_html"/*";
do
if [ ! -f SAME_FILE_IN_$dest_html_DIRECTORY ];
then
cp $f $dest_html;
fi
done
}
The capital letters is where I was stuck.
Thank you very much.
Would the -n option be enough for your needs?
-n, --no-clobber
do not overwrite an existing file (overrides a previous -i option)
use rsync like this:
rsync -c -avz --delete $orig_html $dest_html
which keep $orig_html indentical with $dest_html based file checksum.
Do you need a bash script ? cp supports the -r (recursive) option, and the -u (update) option. From the man page:
-u, --update
copy only when the SOURCE file is newer than the destination
file or when the destination file is missing
Your $f variable contains the full path, because of the /*.
Try doing something like:
for ff in $orig_html/*
do
thisFile=${ff##*/}
if [ ! -f ${dest_html}/$thisFile ]; then
cp $ff ${dest_html}
fi
done

Bash script to safely create symlinks?

I'm trying to store all my profile configuration files (~/.xxx) in git. I'm pretty horrible at bash scripting but I imagine this will be pretty straight forward for you scripting gurus.
Basically, I'd like a script that will create symbolic links in my home directory to files in my repo. Twist is, I'd like it warn and prompt for overwrite if the symlink will be overwriting an actual file. It should also prompt if a sym link is going to be overwritten, but the target path is different.
I don't mind manually editing the script for each link I want to create. I'm more concerned with being able to quickly deploy new config scripts by running this script stored in my repo.
Any ideas?
The ln command is already conservative about erasing, so maybe the KISS approach is good enough for you:
ln -s git-stuff/home/.[!.]* .
If a file or link already exists, you'll get an error message and this link will be skipped.
If you want the files to have a different name in your repository, pass the -n option to ln so that it doesn't accidentally create a symlink in an existing subdirectory of that name:
ln -sn git-stuff/home/profile .profile
...
If you also want to have links in subdirectories of your home directory, cp -as reproduces the directory structure but creates symbolic links for regular files. With the -i option, it prompts if a target already exists.
cp -i -as git-stuff/home/.[!.]* .
(My answer assumes GNU ln and GNU cp, such as you'd find on Linux (and Cygwin) but usually not on other unices.)
The following has race conditions, but it is probably as safe as you can get without filesystem transactions:
# create a symlink at $dest pointing to $source
# not well tested
set -e # abort on errors
if [[ ( -h $dest && $(readlink -n "$dest") != $source ) || -f $dest || -d $dest ]]
then
read -p "Overwrite $dest? " answer
else
answer=y
fi
[[ $answer == y ]] && ln -s -n -f -v -- "$source" "$dest"

Resources