What difference between those two shell commands? - shell

There are two shell commands:
[[ ! -d $TRACEDIR/pattrace/rpt/.tracking ]] && mkdir $TRACEDIR/pattrace/rpt/.tracking
[[ ! -d $TRACEDIR/pattrace/rpt/.tracking ]] && mkdir -p $TRACEDIR/pattrace/rpt/.tracking
Obviously, the only difference between those commands is -p flag. But what this flag does in this context?
Thanks.

From the mkdir man page:
-p, --parents
no error if existing, make parent directories as needed
In other words, if the directories needed don't exist, they will be created as required. If the directories already exist, it won't cause an error.
This is a good place to look for man pages (in addition to using google of course)

mkdir with the -p option will create all necessary parent directories of the specified path, should they not exist (see man pages). Also, with -p you won't get an error if the directory itself already exists.
In your particular case, the first command might fail because the test for the complete path is not sufficient. The test will also fail if only, say, $TRACEDIR/ exists but the subsequent mkdir will the fail because it would require $TRACEDIR/pattrace/rpt/ to exist.
The second command will work, because mkdir -p creates all missing directories "in between" as well.

Related

bash shell generates a link that was not specified

I wrote a simple bash script (in /homedir) to run an executable and then move the outputs to /workdir. I also made a soft link of /workdir named work to /homedir for me to switch easily between folders.
All steps are working well, except that an unspecified soft link named 'grids' is created in /workdir to itself. I can't delete it otherwise all outputs are gone as well.
How can this happen?
#!/bin/bash
cd ..
expname=`basename "$PWD"`
echo 'experiment name: '$expname
homedir=/home/b/b380963/icon_foehn/$expname/grids/
workdir=/work/bb1096/b380963/icon_foehn/$expname/grids/
if [ ! -d ${workdir} ]; then
mkdir -p ${workdir}
fi
cd $homedir
ln -s ${workdir} work
cd /home/b/b380963/nwp/dwd_icon_tools_v2/icontools/
./icongridgen --nml $homedir/gridgen_MCH_july.nml
mv ICON_1E_* $workdir/
mv base_grid* $workdir/
It's quite easy to see in your code:
workdir=/work/bb1096/b380963/icon_foehn/$expname/grids/
...
ln -s ${workdir} work
The command ln -s is the command, creating the symlink.
If you don't like the creation of that symlink, you might put that line in comment (don't delete it: in case you're not satisfied, it's easier to uncomment it).
You can solve your issue, using this command:
ln -sTf ...
This removes the existing destination files beforehand.

Unix Bash Script Create Directory parent and child method

I'm trying to create directory using if condition statement, while running script i am not able to find any expected result from the script, but when i am running manually only mkdir command alone its creating as we expected; here the sample code.
#!/bin/bash
dir_path=/tmp/opt/app/software/{A,B,C,D}
if [[ -d $dir_path ]]; then
mkdir -p /tmp/opt/app/software/{A,B,C,D}
fi
can you please advise, how we can create this..
dir_path is a "list" of directory paths due to the {} parameter expansion. If you write this out:
dir_path=/tmp/opt/app/software/A /tmp/opt/app/software/B /tmp/opt/app/software/C /tmp/opt/app/software/D
This is what's being used in the test of the if statement.
Either you want to iterate over the list of sub directories, or just pass them to mkdir. mkdir simply won't create the directory if it already exists.
Your mkdir command actually expands out to:
mkdir -p /tmp/opt/app/software/A /tmp/opt/app/software/B /tmp/opt/app/software/C /tmp/opt/app/software/D
If you want to itterate and still do a check (which while needless in this example can still be useful other times.)
# Declare the variable `dirs` to be an array and use
# parameter expansion to populate it
declare -a dirs=(/tmp/opt/app/software/{A,B,C,D});
# Iterate over the array of directory names
for dir in ${dirs[#]}; do
if [ ! -d "$dir" ]; then
# The directory does not exsist
mkdir -p "$dir"; # Make the directory
fi
done

shell script - creating folder structure

I wrote this little shell script(test.sh) to create a basic folder structure:
#!/bin/bash
# Check if directory already exists,
# if it doesnt, create one.
if [ ! -d "~/.dir1" ]; then
mkdir ".dir1"
else
rm -rf ".dir1"
mkdir ".dir1"
fi
When I run
test.sh
in console, the hidden folder is created.
But:
When I run it again it tells me:
mkdir: .dir1: File exists
But it could exist because I removed it in my shell script before I created a new one!
So why does it display this message?
Thanks and greetings!
Replace
[ ! -d "~/.dir1" ]
by
[ ! -d "${HOME}/.dir1" ]
I would simply use -p.
mkdir -p "$HOME/dir1"
If you pass -p, mkdir wouldn't throw an error if the directory already exists, it would simply silently return in that case.
If you want to make sure folder is empty use this:
rm -rf "$HOME/dir1"
mkdir -p "$HOME/dir1"
and no if! The basic problem with the if is the fact that it is not immune against race conditions. When the script went off from CPU right after the if - and creates "dir1" - your script will fail when it enters the CPU again since it still thinks the directory does not exist.
What you are doing by "~/.dir1" is not right. It's just another string for a directory name literally "~/.dir1" i.e ~ is not being expanded to $HOME.
Use full path or ~/".dir1" or ~/.dir1 instead.
You can use $HOME too: $HOME/.dir1 or "$HOME/.dir1" or "$HOME"/".dir1" all of them will produce same result... but quoting variables is a good practice.
~ isn't expanded when you place it in quotes. You need to leave it unquoted.
if [ ! -d ~/.dir1 ]
Of note, you're checking for ~/.dir1 but you make .dir1. That's only the same directory if the current directory is ~. If it isn't, they're not the same.
Also, mkdir -p will do this for you, creating a directory only if it doesn't exist already. You could simplify your script to:
mkdir -p ~/.dir1
or
rm -rf ~/.dir1
mkdir ~/.dir1

writing a shell script if statement to check for directory

I need to write a script that will recreate my opt folder if it gets deleted when I remove a package from it. Here's a link to my previous post: dpkg remove to stop processes
Now, the issue I'm running into could be better described here: http://lists.debian.org/debian-devel/2006/03/msg00242.html
I was thinking of just adding a postrem script which checks if an opt directory exists, and if not, creates one. My experience with shell scripts is pretty limited though..
[ -d "$dir" ] || mkdir -p "$dir"
This could be written more verbosely / clearly as:
if ! test -d "$dir"; then
mkdir -p "$dir"
fi
See help test for more information.

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