Skip to content

Instantly share code, notes, and snippets.

@henrjk
Created February 18, 2022 08:14
Show Gist options
  • Save henrjk/c0f2194ab2f92bbde059149c0243efbc to your computer and use it in GitHub Desktop.
Save henrjk/c0f2194ab2f92bbde059149c0243efbc to your computer and use it in GitHub Desktop.
Copy directory tree with cp
#!/bin/bash
set -eu
# this script is meant to be run on macos with gnu cp avalable via gcp (brew install coreutils)
# and macs own cp as cp
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# By default cp -R of directory tree's are not idempotent, so that the second cp does not update the previous one but is copied into an existin directory.
# Lets first create some testdir to be copied in folder 'stuff'
rm -rf stuff
mkdir -p stuff/nm
touch stuff/a
touch stuff/.c
touch stuff/nm/p
touch stuff/nm/.c2
# TODO
# cp -r stuff tdir/tname did no work
# First showcase the problem
init() {
echo "test with $1"
clean_expected_actual
rm -rf tdir && mkdir tdir # this must exist for both gcp and cp
}
clean_expected_actual() {
rm -rf expected && mkdir expected
rm -rf actual && mkdir actual
}
check_results_tdir_tname() {
# -- check results
find tdir/tname > actual/tname
cat << EOF > expected/tname
tdir/tname
tdir/tname/a
tdir/tname/.c
tdir/tname/nm
tdir/tname/nm/.c2
tdir/tname/nm/p
EOF
diff expected/tname actual/tname
}
check_confused_results() {
# -- check results
find tdir/tname > actual/tname-1
cat << EOF > expected/tname-1
tdir/tname
tdir/tname/a
tdir/tname/stuff
tdir/tname/stuff/a
tdir/tname/stuff/.c
tdir/tname/stuff/nm
tdir/tname/stuff/nm/.c2
tdir/tname/stuff/nm/p
tdir/tname/.c
tdir/tname/nm
tdir/tname/nm/.c2
tdir/tname/nm/p
EOF
diff expected/tname-1 actual/tname-1
}
check_results_tdir_tname_stuff() {
find tdir/tname > actual/tname
cat << EOF > expected/tname
tdir/tname
tdir/tname/stuff
tdir/tname/stuff/a
tdir/tname/stuff/.c
tdir/tname/stuff/nm
tdir/tname/stuff/nm/.c2
tdir/tname/stuff/nm/p
EOF
diff expected/tname actual/tname
}
# -- 'naive' cp command
init "'naive' cp command"
cp -r stuff tdir/tname
check_results_tdir_tname
cp -r stuff tdir/tname
check_confused_results
# -- 'naive' cp command when tdir/tname exists
init "'naive' cp command when tdir/tname exists"
mkdir tdir/tname
cp -r stuff tdir/tname
check_results_tdir_tname_stuff
cp -r stuff tdir/tname
check_results_tdir_tname_stuff
# -- 'naive' gnu gcp command
init "same with gcp"
gcp -r stuff tdir/tname
check_results_tdir_tname
gcp -r stuff tdir/tname
check_confused_results
# -- 'naive' gnu gcp command when tdir/tname exists
init "'naive' gnu gcp command when tdir/tname exists"
mkdir tdir/tname
gcp -r stuff tdir/tname
check_results_tdir_tname_stuff
gcp -r stuff tdir/tname
check_results_tdir_tname_stuff
# -- gcp using --no-target-directory
init "gcp using --no-target-directory"
gcp --no-target-directory -r stuff tdir/tname
check_results_tdir_tname
gcp --no-target-directory -r stuff tdir/tname
check_results_tdir_tname
# -- gcp using --no-target-directory with explicit stuff
init "gcp using --no-target-directory with explicit stuff"
mkdir tdir/tname
gcp --no-target-directory -r stuff tdir/tname/stuff
check_results_tdir_tname_stuff
gcp --no-target-directory -r stuff tdir/tname/stuff
check_results_tdir_tname_stuff
# -- gcp using --target-directory
init "gcp using --target-directory"
echo "must create target directory first otherwise fails"
mkdir tdir/tname
gcp --target-directory=tdir/tname -r stuff
# results reflect that the stuff name is kept:
check_results_tdir_tname_stuff
gcp --target-directory=tdir/tname -r stuff
check_results_tdir_tname_stuff
# -- gcp using cmd suggested on sov
init "gcp using cmd suggested on sov"
gcp -r stuff/. tdir/tname
check_results_tdir_tname
gcp -r stuff/. tdir/tname
check_results_tdir_tname
# -- bsd cp using cmd suggested on sov
init "bsd cp using cmd suggested on sov"
cp -r stuff/. tdir/tname
check_results_tdir_tname
cp -r stuff/. tdir/tname
check_results_tdir_tname
#!/bin/bash
set -eu
# this script is meant to be run on macos with gnu cp avalable via gcp (brew install coreutils)
# and macs own cp as cp
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# By default cp -R of directory tree's are not idempotent, so that the second cp does not update the previous one but is copied into an existin directory.
# Lets first create some testdir to be copied in folder 'stuff'
rm -rf stuff
mkdir -p stuff/nm
touch stuff/a
touch stuff/.c
touch stuff/nm/p
touch stuff/nm/.c2
init() {
echo "test with $1"
clean_expected_actual
rm -rf tdir && mkdir tdir # this must exist for both gcp and cp
}
clean_expected_actual() {
rm -rf expected && mkdir expected
rm -rf actual && mkdir actual
}
check_results_tdir_stuff() {
# -- check results
find tdir > actual/tname
cat << EOF > expected/tname
tdir
tdir/stuff
tdir/stuff/a
tdir/stuff/.c
tdir/stuff/nm
tdir/stuff/nm/.c2
tdir/stuff/nm/p
EOF
diff expected/tname actual/tname
}
check_results_tdir() {
find tdir > actual/tname
cat << EOF > expected/tname
tdir
tdir/a
tdir/.c
tdir/nm
tdir/nm/.c2
tdir/nm/p
EOF
diff expected/tname actual/tname
}
# -- test 'naive' cp command
init "'naive' cp command"
cp -r stuff tdir
check_results_tdir_stuff
cp -r stuff tdir
check_results_tdir_stuff
# -- same with gcp
init "same with gcp"
gcp -r stuff tdir
check_results_tdir_stuff
gcp -r stuff tdir
check_results_tdir_stuff
# -- gcp using --no-target-directory
init "gcp using --no-target-directory"
gcp --no-target-directory -r stuff tdir
check_results_tdir
gcp --no-target-directory -r stuff tdir
check_results_tdir
# -- gcp using --target-directory
init "gcp using --target-directory"
gcp --target-directory=tdir -r stuff
# results reflect that the stuff name is kept:
check_results_tdir_stuff
gcp --target-directory=tdir -r stuff
check_results_tdir_stuff
# -- gcp using cmd suggested on sov
init "gcp using cmd suggested on sov"
gcp -r stuff/. tdir
check_results_tdir
gcp -r stuff/. tdir
check_results_tdir
# -- bsd cp using cmd suggested on sov
init "bsd cp using cmd suggested on sov"
cp -r stuff/. tdir
check_results_tdir
cp -r stuff/. tdir
check_results_tdir
@henrjk
Copy link
Author

henrjk commented Feb 18, 2022

The above scripts are meant to reduce confusion about how the cp command works when it copies directory trees.

Some related links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment