Script create tar of a Parent directory which will have individual tar's of its sub directories - linux

I want to write a script which will take two parameters
1. Name of Parent directory (ex. mainFolder)
2. The name of the tar to be created
The parent directory will have subfolers (folder1,folder2,folder3 etc).
I need a script which will create "mainFolder.tar" which will consists of "folder1.tar","folder2.tar","folder3.tar" ...etc...
tar cvf mainFolder.jar mainFolder
this will create tar of parent directly "mainFolder" only...Can anybody tell me how can I make mainFolder.tar to create & contain tar's of its sub directories...Need a Shell Script (ex. createTar.sh)which will do it..
while creating tar, only "directories" inside the parent folder "mainFolder" should be considered for tar..and not ".txt " files..

Here is a POSIX compliant solution for your problem. There may be a simpler way (not using any temporary files) but it would involve special and likely non-portable arguments to tar.
#!/bin/sh
startdir="$(pwd)"
mkdir -p parent/horse/frog parent/dog/frog parent/fish/frog
mkdir newparent
(
cd parent
for i in *
do if [ -d "$i" ]
then tar -cf "$startdir/newparent/${i}.tar" ${i}
fi
if [ -f "$i" ]
then cp "$i" "$startdir/newparent/"
fi
done
)
tar -cf newparent.tar newparent

Related

How to extract, rename and view some log files from user inputed tar filename?

The problem is like this :
I need to extract the logs from a tar archive using user input/argument for the file name (cubelog_457890.tar)
In the archive there is just one folder named tftpboot that I need to rename to the original user input.
After that I need to open and view the log files.
#!/bin/bash
fname=$1
if [ -f $fname ]; then
tar -xvzf $fname
fi
mv tftpboot $fname
If I try to use the script with the argument cubelog_457890.tar I have the problem that the MV line will not work.
Starting the script again and using cubelog_457890 will do the job.
How can I make the MV command take cubelog_457890 from user input without the tar extension?
./extract.sh cubelog_457890.tar - will extract but not rename
./extract.sh cubelog_457890 - will rename the folder
try this:
#!/bin/bash
fname=$1
if [[ -f "${fname}.tar" ]]; then
tar -xvf "${fname}.tar"
fi
mv tftpboot $fname
then ./extract.sh cubelog_457890

How to create a directory and copy files into it with bash

I have some files in Pictures\ with extension *.png and directories like 12-21-20, 12-20-20. These directories was created with dir=mkdir $(date +'%m'-'%d'-'%Y')
At the end of the day I want to run a script which will create a folder $dir and copy all png files I've made for today into that folder. How can I do that? Any information you could give me would be greatly appreciated.
date +'%m-%d-%Y' is the date command outputting, e,g. 12-22-2020. $(..) is called command substitution that captures the result of the date command allowing it to be assigned to the variable dir.
To create a directory with the contents of $dir (e.g. 12-22-2020) you would use the mkdir command, providing the -p option to suppress the error if that directory already exists (and also create parent directories as necessary -- not relevant here). You want to ensure it succeeds before you attempt to copy files to the new directory, so you would use:
mkdir -p "$dir" || exit 1
Which simply exits if the command fails.
At this point, you can simply use cp (or preferably mv to move the files) from whatever source directory they currently reside in. That you can do with:
mv /path/to/source/dir/*.png "$dir"
Or the copy command,
cp -a /path/to/source/dir/*.png "$dir"
Both cp -a and mv will preserve the original file attributes (time, date, permissions, etc...).
From a script standpoint, you will either want to change to the directory above the new "$dir" or use the full path, e.g.
mv /path/to/source/dir/*.png "/path/to/$dir"
Short Example
If you want to provide the directory containing the .png files to move to "$dir" created with today's date, you could write a short script like the following. You provide the directory containing the .png files you would like to copy or move as the first argument to the script on the command-line, e.g. usage would be bash pngscript.sh /path/to/source/dir.
#!/bin/bash
[ -z "$1" ] && { ## validate one argument given for source directory
printf "usage: ./%s /path/to/images" "${0##*/}" >&2
exit 1
}
[ "$(ls -1 "$1"/*.png | wc -l)" -gt 0 ] || { ## validate png files in source dir
printf "error: no .png files in '%s'\n" "$1" >&2
exit 1
}
dir=$(date +'%m-%d-%Y') ## get current date
mkdir -p "$dir" || exit 1 ## create directory, exit on failure
mv "$1"/*.png "$dir" ## move .png files from source to "$dir"
(note: it will create the "$dir" directory below the current working directory and then move files from the path provided as the first argument (positional parameter) to the newly created directory. Change mv to cp -a if you want to leave a copy of the files in the original directory)
You can make the script executable with chmod +x pngscript.sh and then you can simply run it from the current directory as:
./pngscript.sh /path/to/source/dir
Let me know if you have further questions.

Recursively create directory tree within existing subdirectories

I have a working directory with a large number of subfolders (i.e 1190A, 1993A etc).
'/working/1190A'
'/working/1993A'
I would like to recursively create a certain directory tree within each subfolder. For example:
'/working/1190A/analysis/1'
'/working/1993A/analysis/1'
etc
Thanks.
To force the system create a directory tree without having to create each level of it, add -p to the mkdir command.
Hence, this could work:
for dir in list_of_folders
do
mkdir -p $dir/your/directory/tree
[ $? ] && echo "error on $dir" # if the dir could not be created, print error (thanks #hetepeperfan - see comments)
done
Note that the list_of_folders can be given like /working/1190A /working/1993A, but also generated with a find command. This is just a first version you'd better adapt to your specific requirements.
This is one liner as
cd /working
find . -maxdepth 1 -type d -exec mkdir -p '{}'/analysis/1 \;
yourDirList=/working/*
for f in $yourDirList
do
if [ -d $f ]
mkdir -p $f/analysis/1
fi
done

Backing up directories with Bash

I have a function in my .bashrc that I use to backup files:
backup() {
filename=`date +F-%H-%M`-"$#"
/bin/cp -fr "$#" ~/backup/$filename
}
and I would like to make an alias to easily backup a project in the folder foxhound:
alias backfox="backup /home/projects/Foxhound"
I get the error
/bin/cp: cannot create directory `/home/username/backup/2012-01-23-15-03-/home/projects/Foxhound`: No such file or directory
I usually tar/zip the directory with something like this
tar -czf backup-$(date +-%Y-%m%d-%H%Mh%S).tar.gz $filename
then just mv the tar to the backups directory/file server etc.
It makes it easier than dealing a bunch of directories
You may want to add:
mkdir -p $filename
before the cp line.

Is there a way to make mv create the directory to be moved to if it doesn't exist?

So, if I'm in my home directory and I want to move foo.c to ~/bar/baz/foo.c , but those directories don't exist, is there some way to have those directories automatically created, so that you would only have to type
mv foo.c ~/bar/baz/
and everything would work out? It seems like you could alias mv to a simple bash script that would check if those directories existed and if not would call mkdir and then mv, but I thought I'd check to see if anyone had a better idea.
How about this one-liner (in bash):
mkdir --parents ./some/path/; mv yourfile.txt $_
Breaking that down:
mkdir --parents ./some/path
# if it doesn't work; try
mkdir -p ./some/path
creates the directory (including all intermediate directories), after which:
mv yourfile.txt $_
moves the file to that directory ($_ expands to the last argument passed to the previous shell command, ie: the newly created directory).
I am not sure how far this will work in other shells, but it might give you some ideas about what to look for.
Here is an example using this technique:
$ > ls
$ > touch yourfile.txt
$ > ls
yourfile.txt
$ > mkdir --parents ./some/path/; mv yourfile.txt $_
$ > ls -F
some/
$ > ls some/path/
yourfile.txt
mkdir -p `dirname /destination/moved_file_name.txt`
mv /full/path/the/file.txt /destination/moved_file_name.txt
Save as a script named mv.sh
#!/bin/bash
# mv.sh
dir="$2" # Include a / at the end to indicate directory (not filename)
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$#"
Or put at the end of your ~/.bashrc file as a function that replaces the default mv on every new terminal. Using a function allows bash keep it memory, instead of having to read a script file every time.
function mvp ()
{
dir="$2" # Include a / at the end to indicate directory (not filename)
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$#"
}
Example usage:
mv.sh file ~/Download/some/new/path/ # <-End with slash
These based on the submission of Chris Lutz.
You can use mkdir:
mkdir -p ~/bar/baz/ && \
mv foo.c ~/bar/baz/
A simple script to do it automatically (untested):
#!/bin/sh
# Grab the last argument (argument number $#)
eval LAST_ARG=\$$#
# Strip the filename (if it exists) from the destination, getting the directory
DIR_NAME=`echo $2 | sed -e 's_/[^/]*$__'`
# Move to the directory, making the directory if necessary
mkdir -p "$DIR_NAME" || exit
mv "$#"
It sounds like the answer is no :). I don't really want to create an alias or func just to do this, often because it's one-off and I'm already in the middle of typing the mv command, but I found something that works well for that:
mv *.sh shell_files/also_with_subdir/ || mkdir -p $_
If mv fails (dir does not exist), it will make the directory (which is the last argument to the previous command, so $_ has it). So just run this command, then up to re-run it, and this time mv should succeed.
The simpliest way to do that is:
mkdir [directory name] && mv [filename] $_
Let's suppose I downloaded pdf files located in my download directory (~/download) and I want to move all of them into a directory that doesn't exist (let's say my_PDF).
I'll type the following command (making sure my current working directory is ~/download):
mkdir my_PDF && mv *.pdf $_
You can add -p option to mkdir if you want to create subdirectories just like this: (supposed I want to create a subdirectory named python):
mkdir -p my_PDF/python && mv *.pdf $_
Making use of the tricks in "Getting the last argument passed to a shell script" we can make a simple shell function that should work no matter how many files you want to move:
# Bash only
mvdir() { mkdir -p "${#: -1}" && mv "$#"; }
# Other shells may need to search for the last argument
mvdir() { for last; do true; done; mkdir -p "$last" && mv "$#"; }
Use the command like this:
mvdir foo.c foo.h ~/some/new/folder/
rsync command can do the trick only if the last directory in the destination path doesn't exist, e.g. for the destination path of ~/bar/baz/ if bar exists but baz doesn't, then the following command can be used:
rsync -av --remove-source-files foo.c ~/bar/baz/
-a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)
-v, --verbose increase verbosity
--remove-source-files sender removes synchronized files (non-dir)
In this case baz directory will be created if it doesn't exist. But if both bar and baz don't exist rsync will fail:
sending incremental file list
rsync: mkdir "/root/bar/baz" failed: No such file or directory (2)
rsync error: error in file IO (code 11) at main.c(657) [Receiver=3.1.2]
So basically it should be safe to use rsync -av --remove-source-files as an alias for mv.
The following shell script, perhaps?
#!/bin/sh
if [[ -e $1 ]]
then
if [[ ! -d $2 ]]
then
mkdir --parents $2
fi
fi
mv $1 $2
That's the basic part. You might want to add in a bit to check for arguments, and you may want the behavior to change if the destination exists, or the source directory exists, or doesn't exist (i.e. don't overwrite something that doesn't exist).
Sillier, but working way:
mkdir -p $2
rmdir $2
mv $1 $2
Make the directory with mkdir -p including a temporary directory that is shares the destination file name, then remove that file name directory with a simple rmdir, then move your file to its new destination.
I think answer using dirname is probably the best though.
This will move foo.c to the new directory baz with the parent directory bar.
mv foo.c `mkdir -p ~/bar/baz/ && echo $_`
The -p option to mkdir will create intermediate directories as required.
Without -p all directories in the path prefix must already exist.
Everything inside backticks `` is executed and the output is returned in-line as part of your command.
Since mkdir doesn't return anything, only the output of echo $_ will be added to the command.
$_ references the last argument to the previously executed command.
In this case, it will return the path to your new directory (~/bar/baz/) passed to the mkdir command.
I unzipped an archive without giving a destination and wanted to move all the files except demo-app.zip from my current directory to a new directory called demo-app. The following line does the trick:
mv `ls -A | grep -v demo-app.zip` `mkdir -p demo-app && echo $_`
ls -A returns all file names including hidden files (except for the implicit . and ..).
The pipe symbol | is used to pipe the output of the ls command to grep (a command-line, plain-text search utility).
The -v flag directs grep to find and return all file names excluding demo-app.zip.
That list of files is added to our command-line as source arguments to the move command mv. The target argument is the path to the new directory passed to mkdir referenced using $_ and output using echo.
Based on a comment in another answer, here's my shell function.
# mvp = move + create parents
function mvp () {
source="$1"
target="$2"
target_dir="$(dirname "$target")"
mkdir --parents $target_dir; mv $source $target
}
Include this in .bashrc or similar so you can use it everywhere.
Code:
if [[ -e $1 && ! -e $2 ]]; then
mkdir --parents --verbose -- "$(dirname -- "$2")"
fi
mv --verbose -- "$1" "$2"
Example:
arguments: "d1" "d2/sub"
mkdir: created directory 'd2'
renamed 'd1' -> 'd2/sub'
((cd src-path && tar --remove-files -cf - files-to-move) | ( cd dst-path && tar -xf -))
I frequently stumble upon this issue while bulk moving files to new subdirectories. Ideally, I want to do this:
mv * newdir/
Most of the answers in this thread propose to mkdir and then mv, but this results in:
mkdir newdir && mv * newdir
mv: cannot move 'newdir/' to a subdirectory of itself
The problem I face is slightly different in that I want to blanket move everything, and, if I create the new directory before moving then it also tries to move the new directory to itself. So, I work around this by using the parent directory:
mkdir ../newdir && mv * ../newdir && mv ../newdir .
Caveats: Does not work in the root folder (/).
My one string solution:
test -d "/home/newdir/" || mkdir -p "/home/newdir/" && mv /home/test.txt /home/newdir/
i accomplished this with the install command on linux:
root#logstash:# myfile=bash_history.log.2021-02-04.gz ; install -v -p -D $myfile /tmp/a/b/$myfile
bash_history.log.2021-02-04.gz -> /tmp/a/b/bash_history.log.2021-02-04.gz
the only downside being the file permissions are changed:
root#logstash:# ls -lh /tmp/a/b/
-rwxr-xr-x 1 root root 914 Fev 4 09:11 bash_history.log.2021-02-04.gz
if you dont mind resetting the permission, you can use:
-g, --group=GROUP set group ownership, instead of process' current group
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x
-o, --owner=OWNER set ownership (super-user only)
There's a lot of conflicting solutions around for this, here's what worked for us:
## ss_mv ##
function ss_mv {
mkdir -p $(dirname "$2") && mv -f "$#"
}
This assumes commands in the following syntax:
ss_mv /var/www/myfile /var/www/newdir/myfile
In this way the directory path /var/www/newdir is extracted from the 2nd part of the command, and that new directory is then created (it's critical that you use the dirname tag to avoid myfile being added to the new directory being created).
Then we go ahead and mv on the entire string again by using the "$#" tag.
You can even use brace extensions:
mkdir -p directory{1..3}/subdirectory{1..3}/subsubdirectory{1..2}
which creates 3 directories (directory1, directory2, directory3),
and in each one of them two subdirectories (subdirectory1, subdirectory2),
and in each of them two subsubdirectories (subsubdirectory1 and subsubdirectory2).
You have to use bash 3.0 or newer.
$what=/path/to/file;
$dest=/dest/path;
mkdir -p "$(dirname "$dest")";
mv "$what" "$dest"

Resources