writing a shell script if statement to check for directory - shell

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.

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.

Simple BASH script needed: moving and renaming files

Decades ago I was a programmer (IBM assembly, Fortran, COBOL, MS DOS scripting, a bit of Visual Basic.) Thus I'm familiar with the generalities of IF-Then-Else, For loops, etc.
However, I'm now needing to delve into Bash for my current job, and I'm having a difficult time with syntax and appropriate commands for what I need.
I'm in need of a trivial (concept-wise) script, which will:
Determine if a specific folder (e.g., ~/Desktop/Archive Folder) exists on the user Desktop
If not, create it ("Archive")
Move all files/folders on desktop - except for ~/Desktop/Archive, into "Archive Folder" - AND appending a timestamp onto the end of the filenames being moved.
It is this very last piece - the timestamp addition - which is holding me up.
I'm hoping a clear and simple solution can be sent my way. Here is what I've come up with so far:
#!/bin/bash
shopt -s extglob
FOLDERARCH="Archive Folder"
cd ~/Desktop
if [ ! -d $"FOLDERARCH" ]; then
mkdir "$FOLDERARCH"
echo "$FOLDERARCH did not exist, was created"
fi
mv !(-d "$FOLDERARCH") "$FOLDERARCH"
One final note: the script above works (without the timestamp piece) yet also ends with the message
mv: rename Archive Folder to Folder/Archive Folder: Invalid argument
Why?
Any help will be deeply, deeply appreciated. Please assume I know essentially zilch about the BASH environment, cmds and their arguments - this first request for assistance marks my first step into the journey of becoming at least proficient.
Update
First: much gratitude for the replies I've gotten; they've been very useful.
I've now got was it essentially a working version, but with some oddities I do not understand and, after hours of attempted research, have yet to understand/solve.
I'm hoping for some insight; I feel I'm on the verge of making some real headway in comprehending, but these anomalies are hindering my progress. Here's my (working, with "issues") code so far:
shopt -s extglob
FOLDERARCH="Archives"
NEWARCH=$(date +%F_%T)
cd ~/Desktop
if [ ! -d $"FOLDERARCH" ]; then
mkdir "$FOLDERARCH"
echo "$FOLDERARCH did not exist, was created"
fi
mkdir "$FOLDERARCH/$NEWARCH"
mv !(-d "$FOLDERARCH") $FOLDERARCH/$NEWARCH
This in fact largely accomplishes my goal, but:
In the case where the desktop Archives folder already exists, I'm expecting the if-then construct to simply follow through (with no echo msg) to the following mkdir command, but instead the msg "Archives not exist, was created" msg is output anyway (erroneously). Any answers as to why?
The script completes with the following msg:
mv: rename Archives to Archives/2016-01-10_00:06:54/Archives: Invalid argument
I don't understand this at all; what should be happening is that all files/folders on the desktop EXCEPT the /Desktop/Archives folder should be moved into a newly created "subfolder" of /Desktop/Archives, e.g., /Desktop/Archives/2016-01-10_00:06:54. In fact, the move accomplishes my goal, but that the message arises makes no sense to me. What is the invalid argument?
One last note: at this point in my newbie-status I'm looking for code which is clear and easy to read, versus much more elegant/sophisticated one-line piped-command solutions. I look forward to working my way up to those in due time.
You have several options. One of the simplest is to loop over the directories below ~/Desktop and if they are not "$FOLDERARCH", move them to "$FOLDERARCH", e.g.:
for i in */; do
[ "$i" != "$FOLDERARCH"/ ] && mv "$i" "$FOLDERARCH"
done
I haven't run a test case, but something similar to the following should work.
#!/bin/bash
shopt -s extglob
FOLDERARCH="Archive Folder"
cd ~/Desktop || { printf "failed to change to '~/Destop'\n"; exit 1; }
if [ ! -d "$FOLDERARCH" ]; then
if mkdir "$FOLDERARCH" , then
echo "$FOLDERARCH did not exist, was created"
else
echo "error: failed to create '$FOLDERARCH'"
exit 1
fi
fi
for i in */; do
[ "$i" != "$FOLDERARCH"/ ] && mv "$i" "$FOLDERARCH"
done
I apologize, I forgot the datestamp portion. As pointed out in the comments, you can include the datestamp (set the format to your taste) with something similar to the following:
tstamp=$(date +%s)
for i in */; do
[ "$i" != "$FOLDERARCH"/ ] && mv "$i" "$FOLDERARCH/${i}_${tstamp}"
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

What difference between those two shell commands?

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.

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