Bash go to level 1 subdir if inside parentsubdir - bash

Okay,
I would like to do the following in the shell.
If I am in a subdir like css which is inside a subdir like mypage (e.g. projects/mypage/htdocs/css) I would like to go into the root dir of the project, which is mypage. I would like to write this as a function to us as a command. The only "fixed" value is projects.
So basically if I am within any subdir of projects in the shell and I type the command goroot (or whatever) I want the function to check if it is in fact inside a subdir of projects and if so, go to the current subdir.
E.g.
~/projects/mypage/htdocs/css › goroot [hit return]
~/projects/mypage > [jumped to here]
Is this at all possible and if so how could I achieve this?

Assuming I am understanding correctly, this should work:
goroot() { cd $(sed -r 's#(~/projects/[^/]*)/.*#\1#' <<< $PWD); }
This sed command effectively strips off everything after ~/projects/SOMETHING and then changes to that directory. If you're not in ~/projects/ then it will leave you in the current directory.
Note: this assumes that $PWD uses the ~ to denote home, if it is something like /home/user/ then amend the sed command appropriately.

projroot=/home/user/projects
goroot() {
# Strip off project root prefix.
local m=${d#$projroot/}
if [ "$m" = "$d" ]; then
echo "Not in ~/projects"
return
fi
# Strip off project directory.
local suf=${m#*/}
if [ "$suf" = "$m" ]; then
echo "Already in project root."
return
fi
# cd to concatenation of project root, and project directory (stripped of sub-project path).
cd "$projroot/${m%/$suf}"
}

Related

Is it possible to CD into a file?

I find a list of files that I need to cd to (obviously to the parent directory).
If I do cd ./src/components/10-atoms/fieldset/package.json I get the error cd: not a directory:, which makes sense.
But isn't there a way to allow for that? Because manipulating the path-string is pretty cumbersome and to me that would make total sense to have an option for that, since cd is a directory function and it would be cool that if the path would not end up in a file, it would recursively jump higher and find the "first dir" from the given path.
So cd ./src/components/10-atoms/fieldset/package.json would put me into ./src/components/10-atoms/fieldset/ without going on my nerves, telling me that I have chosen a file rather than a dir.
You could write a shell function to do it.
cd() {
local args=() arg
for arg in "$#"; do
if [[ $arg != -* && -e $arg && ! -d $arg ]]; then
args+=("$(dirname "$arg")")
else
args+=("$arg")
fi
done
builtin cd ${args[0]+"${args[#]}"}
}
Put it in your ~/.bashrc if you want it to be the default behavior. It won't be inherited by shell scripts or other programs so they won't be affected.
It modifies cd's arguments, replacing any file names with the parent directory. Options with a leading dash are left alone. command cd calls the underlying cd builtin so we don't get trapped in a recursive loop.
(What is this unholy beast: ${args[0]+"${args[#]}"}? It's like "${args[#]}", which expands the array of arguments, but it avoids triggering a bash bug with empty arrays on the off chance that your bash version is 4.0-4.3 and you have set -u enabled.)
This function should do what you need:
cdd() { test -d "$1" && cd "$1" || cd $(dirname "$1") ; }
If its first argument "$1" is a directory, just cd into it,
otherwise cd into the directory containing it.
This function should be improved to take into account special files such as devices or symbolic links.
You can if you enter a bit longer line (or create dedicated shell script)
cd $(dirname ./src/components/10-atoms/fieldset/package.json)
If you add it in script it can be :
cd $(dirname $1)
but you need to execute it on this way:
. script_name ./src/components/10-atoms/fieldset/package.json
You can put this function in your ~/.bashrc:
function ccd() {
TP=$1 # destination you're trying to reach
while [ ! -d $TP ]; do # if $TP is not a directory:
TP=$(dirname $TP) # remove the last part from the path
done # you finally got a directory
cd $TP # and jump into it
}
Usage: ccd /etc/postfix/strangedir/anotherdir/file.txt will get you to /etc/postfix.

Bash cd .. returns nothing

I have a Bash script:
src="/home/xubuntu/Documents"
mkdir -p "$src/folder1"
src="$src/folder1"
# Do something
printf "SRC IS: $src\n"
src=`cd ..` # RETURN TO PARENT DIRECTORY
printf "SRC IS: $src\n"
Basically I want to create a new folder, then do something inside the folder and after that's done I want to return to the parent directory Documents. For some reason however, src=`cd ..` returns nothing.
SRC IS: /home/xubuntu/Documents
SRC IS:
Any ideas why?
You can access to the parent :
src=$(cd ..&&pwd)
Much better and without using cd:
src=${src%/*} # src is the parent directory
cd is just to change directory, not to display it; that is done with pwd; i.e.
cd ..
src=`pwd`
#or slightly faster
src=$PWD
what is happening is you are assigning the output from the command "cd .." to src
which (as you can see when you do it on the command line) is nothing. Use readlink -f to accomplish what you need.
What you want to do instead is this:
src="/home/xubuntu/Documents"
mkdir -p "$src/folder1"
src="$src/folder1"
# Do something
printf "SRC IS: $src\n"
src=`readlink -f $src/..` # RETURN TO PARENT DIRECTORY
printf "SRC IS: $src\n"
i assume thats what you wanted to do, return the the src it's parent folder.

How to launch a make from a sub dir

I have one top level Makefile. The project has several subdirectories of various depths.
How can I launch make from any subdirectory, so it uses the top level Makefile, just like git finds automatically its top-level .git directory ?
Structure :
/
/a/
/b/c
/Makefile
/Readme
Scenario :
/$ make
... Works ...
/b$ make
... Cannot find makefile
I'd like the 2nd scenario to do the same as the first one.
Hint, it would ideally serve as :make rule in vi, but shouldn't be vi-specific
Update: the / is not the root dir, only the root of the project, the real intent is to mimic git
Hint by Beta would work.
create a alias
alias make=`sh /home/makecrawl.sh`
where makecrawl.sh would look like
#! /bin/bash
while ! [ -f makefile ] && [$PWD != "/" ]
do
cd ..
done
make
#!/bin/bash
HERE=$PWD
while ! [ -f Makefile ] && [ $PWD != "/" ]
do
cd ..
done
MFILE=$PWD/Makefile
cd $HERE
make -f $MFILE

Source bash script to another one [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Reliable way for a bash script to get the full path to itself?
I have bash script test.sh which use functions from another search.sh script by following lines:
source ../scripts/search.sh
<call some functions from search.sh>
Both scripts are located in git repository. search.sh in <git_root>/scripts/ directory, test.sh is located in the same directory (but, generally speaking, could be located anywhere inside <git_root> directory - I mean I can't rely on the following source search.sh approach ).
When I call test.sh script from <git_root>/scripts/ everything works well, but as soon as I change current working directory test.sh fails:
cd <git_root>/scripts/
./test.sh //OK
cd ..
./scripts/test.sh //FAILS
./scripts/test.sh: line 1: ../scripts/search.sh: No file or directory ...
Thus what I have:
Relative path of search.sh script towards <git_root> directory
What I want: To have ability to run test.sh from anywhere inside <git_root> without errors.
P.S.: It is not possible to use permanent absolute path to search.sh as git repository can be cloned to any location.
If both the scripts are in the same directory, then if you get the directory that the running script is in, you use that as the directory to call the other script:
# Get the directory this script is in
pushd `dirname $0` > /dev/null
SCRIPTPATH=`pwd -P`
popd > /dev/null
# Now use that directory to call the other script
source $SCRIPTPATH/search.sh
Taken from the accepted answer of the question I marked this question a duplicatre of: https://stackoverflow.com/a/4774063/440558
Is there a way to identify this Git repository location? An environment variable set? You could set PATH in the script itself to include the Git repository:
PATH="$GIT_REPO_LOCATION/scripts:$PATH"
. search.sh
Once the script is complete, your PATH will revert to its old value, and $GIT_REPO_LOCATION/scripts will no longer be part of the PATH.
The question is finding this location to begin with. I guess you could do something like this in your script:
GIT_LOCATION=$(find $HOME -name "search.sh" | head -1)
GIT_SCRIPT_DIR=$(dirname $GIT_LOCATION)
PATH="$GIT_SCRIPT_DIR:$PATH"
. search.sh
By the way, now that $PATH is set, I can call the script via search.sh and not ./search.sh which you had to do when you were in the scripts directory, and your PATH didn't include . which is the current directory (and PATH shouldn't include . because it is a security hole).
One more note, you could search for the .git directory too which might be the Git repository you're looking for:
GIT_LOCATION=$(find $HOME -name ".git" -type d | head -1)
PATH="$GIT_LOCATION:$PATH"
. search.sh
You could do this:
# Get path the Git repo
GIT_ROOT=`git rev-parse --show-toplevel`
# Load the search functions
source $GIT_ROOT/scripts/search.sh
How get Git root directory!
Or like #Joachim Pileborg says, but you have to pay attention that you must know the path of this one to another script;
# Call the other script
source $SCRIPTPATH/../scripts/search.sh
# Or if it is in another path
source $SCRIPTPATH/../scripts/seachers/search.sh
The Apache Tomcat scripts use this approach:
# resolve links - $0 may be a softlink
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
Any way, you have to put this snippet on all scripts that use other scripts.
For the people who would rather not use git's features for finding the parent directory. If you can be sure you'll always be running the script from within the git directory, you can use something like this:
git_root=""
while /bin/true ; do
if [[ "$(pwd)" == "$HOME" ]] || [[ "$(pwd)" == "/" ]] ; then
break
fi
if [[ -d ".git" ]] ; then
git_root="$(pwd)"
break
fi
cd ..
done
I haven't tested this but it will just loop back until it hits your home directory or / and it will see if there is a .git directory in each parent directory. If there is, it sets the git_root variable and it will break out. If it doesn't find one, git_root will just be an empty string. Then you can do:
if [[ -n "$git_root" ]] ; then
. ${git_root}/scripts/search.sh
fi
IHTH

Save current directory in variable using Bash?

What I'm trying to do is find the current working directory and save it into a variable, so that I can run export PATH=$PATH:currentdir+somethingelse. I'm not entirely sure if they have a variable that contains cwd by default.
How do I save the current directory in variable using Bash?
This saves the absolute path of the current working directory to the variable cwd:
cwd=$(pwd)
In your case you can just do:
export PATH=$PATH:$(pwd)+somethingelse
I have the following in my .bash_profile:
function mark {
export $1=`pwd`;
}
so anytime I want to remember a directory, I can just type, e.g. mark there .
Then when I want to go back to that location, I just type cd $there
current working directory variable ie full path /home/dev/other
dir=$PWD
print the full path
echo $dir
Your assignment has an extra $:
export PATH=$PATH:${PWD}:/foo/bar
for a relative answer, use .
test with:
$ myDir=.
$ ls $myDir
$ cd /
$ ls $myDir
The first ls will show you everything in the current directory, the second will show you everything in the root directory (/).
On a BASH shell, you can very simply run:
export PATH=$PATH:`pwd`/somethingelse
No need to save the current working directory into a variable...
One more variant:
export PATH=$PATH:\`pwd`:/foo/bar
You can use shell in-build variable PWD, like this:
export PATH=$PATH:$PWD+somethingelse
Similar to solution of mark with some checking of variables. Also I prefer not to use $variable but rather the same string I saved it under
save your folder/directory using save dir sdir myproject and go back to that folder using goto dir gdir myproject
in addition checkout the workings of native pushd and popd they will save the current folder and this is handy for going back and forth. In this case you can also use popd after gdir myproject and go back again
# Save the current folder using sdir yourhandle to a variable you can later access the same folder fast using gdir yourhandle
function sdir {
[[ ! -z "$1" ]] && export __d__$1="`pwd`";
}
function gdir {
[[ ! -z "$1" ]] && cd "${!1}";
}
another handy trick is to combine the two pushd/popd and sdir and gdir wher you replace the cd in the goto dir function in pushd. This enables you to also fly back to your previous folder when making the jump to the saved folder.
# Save the current folder using sdir yourhandle to a variable you can later access the same folder fast using gdir yourhandle
function sdir {
[[ ! -z "$1" ]] && export __d__$1="`pwd`";
}
function gdir {
[[ ! -z "$1" ]] && pushd "${!1}";
}

Resources