Cannot Create Directories On Ubuntu With Bash Shell Script - bash

I'm trying to run this bash shell script to create directories for vim syntax highlighting on Ubuntu 13.04 (via Vagrant 1.4.1 on Windows 7).
#!/usr/bin/env bash
basevim="$HOME/.vim"
ftdetect="${basevim}/ftdetect"
indent="${basevim}/indent"
syntax="${basevim}/syntax"
echo "Setting up VIM for syntax highlighting"
#Create directories for vim syntax highlighting
if [ ! -d "$basevim" ]; then
echo "Adding VIM syntax highlighting dirs"
mkdir "$basevim"
mkdir "$ftdetect"
mkdir "$indent"
mkdir "$syntax"
else
if [ ! -d "$ftdetect" ]; then
mkdir "$ftdetect"
fi
if [ ! -d "$indent" ]; then
mkdir "$indent"
fi
if [ ! -d "$syntax" ]; then
mkdir "$syntax"
fi
fi
This is executing as a provision.sh script for Vagrant so as far as I know it should run as root. I can see the echo'd message so it's taking the first branch. But for the life of me I can't seem to get this to work; no complaints but the directories don't get created. If I set those variables on an interactive prompt, I need to do sudo mkdir ftdetect (etc.) to get the directories created. Strangely I don't need to sudo to get the .vim directory created--at least that's what I recall.
I tried
if [ ! -d "${basevim}" ]; then
but that didn't do anything. I also tried
basevim="{$HOME}/.vim"
--also no dice. Any thoughts of what I may be missing? As I say, as far as I know it shouldn't be necessary to sudo on a provisioning script on Vagrant. I can tell the script is getting run because those echo'd messages are getting output.

Your script could be replaced by
mkdir -p "$HOME/.vim"/{ftdetect,indent,syntax}
As for the directories not appearing... Where are you looking for them?
Running this as root would create them in root's home directory, /root/, and not in the user's home directory /home/username. When in doubt, use absolute path names (and chown as needed afterwards).

Related

Why my file does not get sourced from bash script?

I have a bash script where at some point, I want to source the ${HOME}/.profile file which should add ${HOME}/.local/bin to the $PATH. But when I check the path with echo $PATH, ${HOME}/.local/bin is absent as if the source did not happen. What am I doing wrong?
if command -v pip3 &>/dev/null; then
echo "Pip is already installed."
else
echo "Pip is not installed. Installing Pip..."
cd ${HOME}/Downloads
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
su -c "python3 get-pip.py --user" "$SUDO_USER"
cat <<-'EOT' >> "${HOME}/.profile"
# set PATH so it includes user's private .local/bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
EOT
source "${HOME}/.profile" #this is not happening!!!
rm ${HOME}/Downloads/get-pip.py
echo "Pip has been installed."
fi
Thanks in advance.
EDIT: Fixed the script syntax as suggest by Kusalananda.
A script can't modify the environment of the shell from whence it was executed.
Sourcing ~/.profile in the script will not set the path in the interactive shell that originally started the script. To do that, you would have to source your script.
Also, your here-document would need to be quoted, or the current values of HOME and PATH would be inserted into the .profile file:
cat <<'PROFILE_END' >> "$HOME/.profile"
# set PATH so it includes user's private .local/bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
PROFILE_END
Also note that if the user is a bash user with an existing ~/.bash_profile file, then the ~/.profile file will be ignored for that user when a new login shell is started.
I'm further unsure why you su to $USER. It seems like an unnecessary step.

Getting test: too many arguments error while checking existence of directory in shell script

I am trying to write a shell script for extraction of .tar.gz file. I need to check first that if same directory is not present then extract the zip file. Otherwise do some thing else. Below is my shell script.
#!/bin/bash
INSTALL_DIR=$HOME/Test/LogShipper
LOGSTASH_PATH=logstash-2.3.2
LOGSTASH_FOLDER=$HOME/Test/LogShipper/logstash
LOGSTASH_BINARY=$LOGSTASH_PATH.tar.gz
ES_PATH=elasticsearch-2.3.2
ES_BINARY=$ES_PATH.tar.gz
KIBANA_VERSION=kibana-4.5.0
KIBANA_OS=darwin-x64
KIBANA_BINARY=$KIBANA_VERSION-$KIBANA_OS
echo Installing ELK stack into $INSTALL_DIR
mkdir -p $INSTALL_DIR
cd $INSTALL_DIR
if test [! -d "$LOGSTASH_FOLDER" ];
then
if test -s $LOGSTASH_BINARY
then
echo Logstash Zip Exists
echo Now installing...
echo Unpacking logstash...
tar zxf $LOGSTASH_BINARY $LOGSTASH_FOLDER
echo Unpacking Completed.
else
echo Downloading logstash 2.3.2
curl -O https://download.elasticsearch.org/logstash/logstash/$LOGSTASH_BINARY
fi
else
echo Logstash already installed.
fi
I am getting error test: too many arguments at line if test [! -d "$LOGSTASH_FOLDER" ];
You probably don't need to use test when using [] as it implicitly invokes the same during evaluation. Also include a space after open brace [.
if [ ! -d "$LOGSTASH_FOLDER" ];
You can explicitly use test command the following way, try
if ! test -d "$LOGSTASH_FOLDER"
If "$HOME" has any spaces in it, and were unquoted (as it is in the given code), that would cause the error in question. Suggest changing:
INSTALL_DIR=$HOME/Test/LogShipper
...
LOGSTASH_FOLDER=$HOME/Test/LogShipper/logstash
...
mkdir -p $INSTALL_DIR
...
cd $INSTALL_DIR
To:
INSTALL_DIR="$HOME"/Test/LogShipper
...
LOGSTASH_FOLDER="$HOME"/Test/LogShipper/logstash
...
mkdir -p "$INSTALL_DIR"
...
cd "$INSTALL_DIR"

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.

How to change current working directory inside command_not_found_handle

I'm trying to write a not found handle in Bash that does the following:
If $1 exists and it's a directory, cd into it.
If $1 exists inside a user defined directory $DEV_DIR, `cd into it.
If the previous conditions don't apply, fail.
Right now I have something like this:
export DEV_DIR=/Users/federico/programacion/
function command_not_found_handle () {
if [ -d $1 ]; then # the dir exists in '.'
cd $1
else
to=$DEV_DIR$1
if [ -d $to ]; then
cd $to
echo `pwd`
else
echo "${1}: command not found"
fi
fi
}
And although it seems to be working (the echo pwd command prints the expected dir), the directory in the actual shell does not change.
I was under the impression that since this is a function inside my .bashrc the shell wouldn't fork and I could do the cd but apparently that's not working. Any tips on how to solve this would be appreciated.
I think what's going on is that the shell fork()s after setting up any redirections but before looking for commands, so command_not_found_handle can't affect the interactive shell process.
What you seem to want to do may partly possible using the autocd feature:
shopt -s autocd
From man bash:
autocd - If set, a command name that is the name of a directory
is executed as if it were the argument to the cd com‐
mand. This option is only used by interactive shells.
Otherwise, just create a function that you invoke by name that performs the actions you are trying to use command_not_found_handle for.
It won't change directies if you run this program as a script in your main shell because it creates a sub-shell when it executes. If you source the script in your current shell then it will have the desired effect.
~/wbailey> source command_not_found.sh
That said, I think the following would achieve the same result:
wesbailey#feynman:~/code_katas> cd xxx 2> /dev/null || cd ..; pwd
/Users/wesbailey
just replace the ".." with your env var defined directory and create an alias in your .bashrc file.
I've had the very same wish and the solution that I've been using for a while was opening a new tab in gnome terminal by issuing the command gnome-terminal --tab --working-directory="$FOLDER" from inside the command_not_found handle.
But today I've come up with a solution which is not tied to a specific terminal application, but has exactly the intended behaviour.
The solution uses the PROMPT_COMMAND, which is run before each prompt. The PROMPT_COMMAND is bound to a function responsible for checking for a file related to current shell, and cd'ing into the directory specified in that file.
Then, the command_not_found_handle fills in the file when a change in directory is desired. My original command_not_found_handle also checkout a git branch if the current directory is a git repository and the name matches an existing branch. But to keep focus on answering the current question, I've stripped that part of code.
The command_not_found_handle uses find for searching for the directory matching the given name and goes only 2 levels deep in the directory tree, starting from a configured list.
The code to be added to bash_rc follows:
PROMPT_COMMAND=current_shell_cd
CD_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/bash-cd/$$.cd"
current_shell_cd() {
if [ -r "$CD_FILE" ]; then
local CD_TARGET="$( cat "$CD_FILE" )"
[ ! -z "$CD_TARGET" ] && cd "$CD_TARGET" 2>/dev/null
rm "$CD_FILE"
fi
}
command_not_found_handle () {
local COMMAND="$1";
# List folders which are going to be checked
local BASE_FOLDER_LIST=(
"$HOME/Desenvolvimento"
"/var/www/html"
"$HOME/.local/opt/"
)
local FOLDER=$(
find "${BASE_FOLDER_LIST[#]}" \
-maxdepth 2 -type d \
-iname "$COMMAND" -print -quit )
if [ ! -z "$FOLDER" -a -d "$FOLDER" ]
then
mkdir -p "$( dirname "$CD_FILE" )"
echo "$FOLDER" > "$CD_FILE"
else
printf "%s: command not found\n" "$1" 1>&2
return 127
fi
}

Resources