Linux (ubuntu): copying directory to another directory which does not exist - linux

I am going through linux tutorial, and in it is written that cp -r dir1 dir2 will copy directory dir1 into dir2, and if dir2 does not exist then dir2 will be created and then dir1 will be copied to dir2.
However when I try in my ubuntu 12.04 system this is not happening.
sps#sps-Inspiron-N5110:~$ ls | grep dir
sps#sps-Inspiron-N5110:~$ mkdir dir1
sps#sps-Inspiron-N5110:~$ ls | grep dir
dir1
sps#sps-Inspiron-N5110:~$ cp -r dir1 dir2
sps#sps-Inspiron-N5110:~$ ls | grep dir
dir1
dir2
sps#sps-Inspiron-N5110:~$ ls ./dir2
sps#sps-Inspiron-N5110:~$
So you see that although dir2 is created, it is empty. Confirming this below.
sps#sps-Inspiron-N5110:~$ cd dir2
sps#sps-Inspiron-N5110:~/dir2$ ls
sps#sps-Inspiron-N5110:~/dir2$
Could someone tell me if this is expected or something is going wrong ? Why is dir1 not copied to dir2 ?
Thanks.

Related

Copy files and preserving directory structure

Here's what I have to do: Find all files which are in the directory src (or in its subdirectories) and have str in their name and copy them to dest preserving the subdirectory structure. For example I have the directory dir1 which contains foo.txt and the subdirectory subdir which also contains foo.txt. After running my script (with str=txt and dest=dir2) dir2 should countain foo.txt and subdir/foo.txt. So far I have come up with this code:
while read -r line; do
cp --parents $line $dest
done <<< "$(find $src -name "*$str*")"
which almost does the job except that it creates dir1 inside of dir2 and the desired files are inside dir2/dir1. I also tried doing it with the -exec option of find but didn't get better results.
IIUC, this can be done with find ... -exec. Let's say we have the following directory:
$ tree
.
└── src
├── dir1
│   └── yet_another_file_src
└── file_src
2 directories, 2 files
We can copy all files that contain *src* to /tmp/copy-here like this:
$ find . -type f -name "*src*" -exec sh -c 'echo mkdir -p /tmp/copy-here/$(dirname {})' \; -exec sh -c 'echo cp {} /tmp/copy-here/$(dirname {})' \;
mkdir -p /tmp/copy-here/./src
cp ./src/file_src /tmp/copy-here/./src
mkdir -p /tmp/copy-here/./src/dir1
cp ./src/dir1/yet_another_file_src /tmp/copy-here/./src/dir1
Notice that I used echo instead of really running this command -
read the output and make sure that this is what you want to
achieve. If you're sure that this would be what you want just remove
echo like this:
$ find . -type f -name "*src*" -exec sh -c 'mkdir -p /tmp/copy-here/$(dirname {})' \; -exec sh -c 'cp {} /tmp/copy-here/$(dirname {})' \;
$ tree /tmp/copy-here
/tmp/copy-here
└── src
├── dir1
│   └── yet_another_file_src
└── file_src
2 directories, 2 files
EDIT:
And of course, you can always use rsync:
$ rsync -avz --include "*/" --include="*src*" --exclude="*" "$PWD" /tmp/copy-here

Linux command to find the difference between two folders

I have two folders, each with sub folders, and I want to see if there are any sub folders in one file that does not exist the other folder. I have tried this command:
diff -r file1 file2
but it does not provide the results that I want.
For example if file1 contains three folders A, B, and C and file 2 contains 1 folder B, then the output should be folders A and C.
diff -r dir1 dir2 | grep dir1 | awk '{print $4}' > difference1.txt
Explanation:
diff -r dir1 dir2 shows which files are only in dir1 and those
only in dir2 and also the changes of the files present in both directories if any.
diff -r dir1 dir2 | grep dir1 shows which files are only in dir1
awk to print only filename.

Shell: Copy Certain Types of Files Keeping Directory Structure

Say I have a folder following the structure below:
$ ls /tmp/level1
level2_folder1 level2_folder2
$ ls /tmp/level1/level2_folder1
input output script.py ...
$ ls /tmp/level1/level2_folder2
input output script.py ...
I want to copy all the Python scripts ONLY to somewhere else but keeping the existing structure. Let's say I want to copy the level1 folder to home/ so it should looks like this:
$ ls /home/level1
level2_folder1 level2_folder2
$ ls /home/level1/level2_folder1
script.py
$ ls /home/level1/level2_folder2
script.py
How could I do that?
rsync -avz --include "*/" --include "*.py" --exclude "*" /tmp/level1 /home
cd /tmp && find level1 -name '*.py' -print0 | cpio -pd0 /home

How I can pack into tar-file only last directory from path?

How I can pack into tar-file only last directory from path?
For example, I have several paths
/usr/local/files/dir1/
file1.txt
file2.txt
file3.txt
/usr/local/files/dir2/
file3.txt
file4.txt
file5.txt
if I run command:
tar czf my_arch.tar.gz -C /usr/local/files/dir1 .
I gain only containment of dir1 catalog, without itself.
So I have - my_arch.tar.gz/file1.txt, file2.txt, file3.txt, But I need structure like that inside my archive -
my_arch.tar.gz/dir1/file1.txt, file2.txt, file3.txt
How I can do this?
Thank you.
try
cd /usr/local/files
tar -cvzf my_arch.tar.gz dir1
The -C directive will make you change into dir1 and thus not archive the folder, but its contents:
-C, --directory DIR
change to directory DIR
you cannot do this directly through tar.
here's my suggestion :
#!/bin/bash
mydir=/my_dir/whit/long_and/complicated_path/the_stuff_is_here
dirname=$(dirname $mydir )
basename=$(basename $mydir )
tar cvf /tmp/$basename.tar -C $dirname $basename
$ tar vczf tmp/export/files.tar.gz -C tmp/export src
structure for files.tar.gz
src
src/app
src/app/main.js
src/app/util
src/app/util/runtime.js
If I understand what you are asking correctly, you want your tar file to contain the directory.
Try it without the -C flag as in:
tar -czf my_arch.tar.gz /usr/local/files/dir1
If you specify -C then you directory path is ./. Probably the following works like you want:
$ touch asdf/foo/bar/{1,2,3}
$ tree asdf/
asdf/
└── foo
└── bar
├── 1
├── 2
└── 3
2 directories, 3 files
$ tar -cv -C asdf/foo/bar/ -f asdf.tar ./
./
./3
./2
./1
$ tar tf asdf.tar
./
./3
./2
./1

diff to output only the file names

I'm looking to run a Linux command that will recursively compare two directories and output only the file names of what is different. This includes anything that is present in one directory and not the other or vice versa, and text differences.
From the diff man page:
-q Report only whether the files differ, not the details of the differences.
-r When comparing directories, recursively compare any subdirectories found.
Example command:
diff -qr dir1 dir2
Example output (depends on locale):
$ ls dir1 dir2
dir1:
same-file different only-1
dir2:
same-file different only-2
$ diff -qr dir1 dir2
Files dir1/different and dir2/different differ
Only in dir1: only-1
Only in dir2: only-2
You can also use rsync
rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out
If you want to get a list of files that are only in one directory and not their sub directories and only their file names:
diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'
If you want to recursively list all the files and directories that are different with their full paths:
diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'
This way you can apply different commands to all the files.
For example I could remove all the files and directories that are in dir1 but not dir2:
diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}
The approach of running diff -qr old/ new/ has one major drawback: it may miss files in newly created directories. E.g. in the example below the file data/pages/playground/playground.txt is not in the output of diff -qr old/ new/ whereas the directory data/pages/playground/ is (search for playground.txt in your browser to quickly compare). I also posted the following solution on Unix & Linux Stack Exchange, but I'll copy it here as well:
To create a list of new or modified files programmatically the best solution I could come up with is using rsync, sort, and uniq:
(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
Let me explain with this example: we want to compare two dokuwiki releases to see which files were changed and which ones were newly created.
We fetch the tars with wget and extract them into the directories old/ and new/:
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1
Running rsync one way might miss newly created files as the comparison of rsync and diff shows here:
rsync -rcn --out-format="%n" old/ new/
yields the following output:
VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php
Running rsync only in one direction misses the newly created files and the other way round would miss deleted files, compare the output of diff:
diff -qr old/ new/
yields the following output:
Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ
Running rsync both ways and sorting the output to remove duplicates reveals that the directory data/pages/playground/ and the file data/pages/playground/playground.txt were missed initially:
(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
yields the following output:
VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php
rsync is run with theses arguments:
-r to "recurse into directories",
-c to also compare files of identical size and only "skip based on checksum, not mod-time & size",
-n to "perform a trial run with no changes made", and
--out-format="%n" to "output updates using the specified FORMAT", which is "%n" here for the file name only
The output (list of files) of rsync in both directions is combined and sorted using sort, and this sorted list is then condensed by removing all duplicates with uniq
On my linux system to get just the filenames
diff -q /dir1 /dir2|cut -f2 -d' '
I have a directory.
$ tree dir1
dir1
├── a
│   └── 1.txt
├── b
│   └── 2.txt
└── c
├── 3.txt
├── 4.txt
└── d
└── 5.txt
4 directories, 5 files
I have another directory.
$ tree dir2
dir2
├── a
│   └── 1.txt
├── b
└── c
├── 3.txt
├── 5.txt
└── d
└── 5.txt
4 directories, 4 files
I can diff two directories.
$ diff <(cd dir1; find . -type f | sort) <(cd dir2; find . -type f| sort)
--- /dev/fd/11 2022-01-21 20:27:15.000000000 +0900
+++ /dev/fd/12 2022-01-21 20:27:15.000000000 +0900
## -1,5 +1,4 ##
./a/1.txt
-./b/2.txt
./c/3.txt
-./c/4.txt
+./c/5.txt
./c/d/5.txt
rsync -rvc --delete --size-only --dry-run source dir target dir

Resources