I'm looking for a command that would create a directory and bring me to it directly after, similar to:
$ mkdir project-one-business-dev-2
$ cd project-one-business-dev-2
I don't want to type the project's name twice because it's too long (I know I can use tab, but what if there are similar names?). Maybe only one command can do it.
A process can't change the working directory of it's parent process. That makes it impossible for an external command like mkdir to set the working directory of the calling shell to the newly created folder.
But you can create a bash function for that purpose. Put this for example into your .bashrc:
mkcd() {
mkdir -p "${1}"
cd "${1}"
}
You can do it like this:
mkdir project-one-business-dev-2 && cd "$_"
for more information check out this post on AskUbuntu
Related
I have a shell script myautoappupgrade.sh where I automate a process of application upgrade. The script has to be run on few different servers. Unfortunately, the application is located in slightly different directory on each server - the number for parent directory varies between 1-20. How I can modify the script, so that the directory can be replaced by some sort of variable? I don't want to edit the script for each server because there are many directory queries in the automation script.
example:
cd /ae1/apps/myapp/upgradefiles/
unzip file.zip
./install.sh
the directory slightly changes on another server:
cd /ae2/apps/myapp/upgradefiles/
unzip file.zip
./install.sh
and another..
cd /ae3/apps/myapp/upgradefiles/
unzip file.zip
./install.sh
Try something like this:
#!/bin/bash
num=$1
cd /ae${num}/apps/myapp/upgradefiles/file.zip
unzip file.zip
./install.sh
Then call the script with the number as first argument:
myautoappupgrade.sh 1
The simple and obvious solution is to not hard-code the directory at all. Modify the script so it accepts the parent directory as an argument, or just cd into the parent directory before running the script.
Perhaps something like this:
while read server dir; do
ssh "$server" "cd '$dir' && unzip apps/myapp/upgradefiles/file.zip/file.zip && ./install.sh"
done <<\:
ernie /ae1
bert /ae2
cookiemonster /home/cmonster/anN
:
It would probably be even better if you unzipped into a temporary directory, but hopefully this should get you moving in the right direction.
Of course, if you can be sure that /ae[0-1] is always there and there is only one match,
cd /ae[0-9]/apps/myapp/upgradefiles/file.zip
would do what you are asking.
(Do you really have a file named file.zip inside a directory also named file.zip? I'm guessing actually take away the file.zip from the end of the cd path.)
By simply using:
cd /ae*/apps/myapp/upgradefiles/
The * will expand any character.
When compiling, I always place the build in a separate directory. For example:
mkdir build
cd ./build
(cd ..; ./bootstrap)
../configure
make
Since I have plenty of RAM the aim is to compile on a TMPFS.
The script gets the name of the project, uses it for the name for the directory created in $XDG_RUNTIME_DIR/build and finally links it.
# setup-build.sh
#!/usr/bin/bash
set -e
my_project_name=$(basename $(pwd))
my_project_build_dir="$XDG_RUNTIME_DIR/build/$my_project_name"
mkdir -p $my_project_build_dir
ln -s "$my_project_build_dir" "$(pwd)/build"
The script runs without a problem. But, when I do cd ./build; ../configure it returns an error: bash: ../configure: No such file or directory. The file most certainly does exist, but Bash can't find it!
I altered the script to this:
#!/usr/bin/bash
set -e
my_project_src_dir="$(pwd)"
my_project_name="$(basename $(pwd))"
my_project_build_dir="$XDG_RUNTIME_DIR/build/$my_project_name"
mkdir -p "$my_project_build_dir"
ln -s "$my_project_build_dir" "$(pwd)/build"
cd "$my_project_build_dir"
echo "$my_project_src_dir" > "./project-src-dir.txt"
To compile I have to type cd ./build; $(cat ./project-src-dir.txt)/configure; make. This causes Bash complete to partial break, though. As in I can't TAB complete file names from $my_project_src_dir with this method, but TAB completion for arguments works fine. Ifautoconf is needed: (cd $(cat ./project-src-dir.txt); ./bootstrap). If anyone has any other ideas I would still prefer to be able to just do ../configure, although this will have to do for now.
Edit: Had to change my_project_name="$(basename '$my_project_src_dir') to my_project_name="$(basename $(pwd))" as it was taking '$my_project_src_dir' literally.
I'm searching for just one command — nothing with && or | — that creates a directory and then immediately changes your current directory to the newly-created directory. (This is a question someone got for his exams of "linux-usage", he made a new command that did that, but that didn't give him the points.) This is on a debian server if that matters.
I believe you are looking for this:
mkdir project1 && cd "$_"
define a bash function for that purpose in your $HOME/.bashrc e.g.
function mkdcd () {
mkdir "$1" && cd "$1"
}
then type mkdcd foodir in your interactive shell
So stricto sensu, what you want to achieve is impossible without a shell function containing some && (or at least a ; ) ... In other words, the purpose of the exercise was to make you understand why functions (or aliases) are useful in a shell....
PS it should be a function, not a script (if it was a script, the cd would affect only the [sub-] shell running the script, not the interactive parent shell); it is impossible to make a single command or executable (not a shell function) which would change the directory of the invoking interactive parent shell (because each process has its own current directory, and you can only change the current directory of your own process, not of the invoking shell process).
PPS. In Posix shells you should remove the functionkeyword, and have the first line be mkdcd() {
For oh-my-zsh users: take 'directory_name'
Reference: Official oh-my-zsh github wiki
Putting the following into your .bash_profile (or equivalent) will give you a mkcd command that'll do what you need:
# mkdir, cd into it
mkcd () {
mkdir -p "$*"
cd "$*"
}
This article explains it in more detail
I don't think this is possible but to all people wondering what is the easiest way to do that (that I know of) which doesn't require you to create your own script is:
mkdir /myNewDir/
cd !$
This way you don't need to write the name of the new directory twice.
!$ retrieves the last ($) argument of the last command (!).
(There are more useful shortcuts like that, like !!, !* or !startOfACommandInHistory. Search on the net for more information)
Sadly mkdir /myNewDir/ && cd !$ doesn't work: it retrieves the last of argument of the previous command, not the last one of the mkdir command.
Maybe I'm not fully understanding the question, but
>mkdir temp ; cd temp
makes the temp directory and then changes into that directory.
mkdir temp ; cd temp ; mv ../temp ../myname
You can alias like this:
alias mkcd 'mkdir temp ; cd temp ; mv ../temp ../'
You did not say if you want to name the directory yourself.
cd `mktemp -d`
Will create a temp directory and change into it.
Maybe you can use some shell script.
First line in shell script will create the directory and second line will change to created directory.
Here's the end result I am trying to:
I have over 15 users of an cloned instance of my application, sometimes I need to update files (they pretty much all stay the same--everything is dynamic. This is for updates/new features). I wrote a pretty simple bash script that I had to manually put each user from /home/ into the array. But I need this to scale.
How can I take a directory listing (something like a LS command) feed ONLY DIRECTORY names into then a bash array. Likely i'll want this command in the bash file though, because I'll want it to grab all users in the /home/ directory, push into the array (eg: webUsers( adam john jack )
Here's a snapshot of what my current script looks like (non-dynamic user listing)
webUsers( adam john jack )
for i in "${webUsers[#]}"
do
cp /home/mainSource/public_html/templates/_top.tpl /home/$i/public_html/templates
done
How do I achieve this?
Do this:
webUsers=(/home/*/)
and the contents will look like:
$ declare -p webUsers
declare -a webUsers='([0]="/home/adam/" [1]="/home/jack/" [2]="/home/john")'
$ echo ${webUsers[1]}
/home/jack/
Or, if you don't want the parent directory:
pushd /home
webUsers=(*/)
popd
and you'll get:
$ declare -p webUsers
declare -a webUsers='([0]="adam/" [1]="jack/" [2]="john")'
$ echo ${webUsers[1]}
jack/
The following script will loop over all users with directories in /home. It will also unconditionally try to create the /public_html/templates directory. If it doesn't yet exist, it will get created. If it does exist, this command does essentially nothing.
#!/bin/bash
cd /home
userarr=( */ );
for user in "${userarr[#]%*/}"; do
mkdir -p "/home/${user}/public_html/templates"
cp "/home/mainSource/public_html/templates/_top.tpl /home/${user}/public_html/templates"
done
It may be easier to make a link to the source directory, and then you can just update it in one place.
Just set up each users directory so that the common files are all pulled from a directory called common_files (or whatever you like), and then run this command in each home directory:
ln -s /location/of/files/they/need common_files
update /location/of/files/they/need and it automatically propagates.
With bash you can actually make this pretty short and simple. To list the current directory and store it into an array:
ls . | readarray i
or
ls . | bash -c 'readarray i'
To use the data:
ls . | bash -c 'readarray i && for j in ${i[*]}; do <-command->; done'
I wrote my own custom post-merge hook, now I added a "hooks" directory to my main project folder (since git doesn't track changes in .git/hooks), somewhere I read that I can make a symbolic link from hooks to .git/hooks so I don't have to copy the file from one folder to the other every time someone changes it so I tried:
ln -s -f hooks/post-merge .git/hooks/post-merge
But it doesn't seem to work, any ideas why? "ln hooks/post-merge .git/hooks/post-merge" works fine but making a hard link is the same as copyin I guess....
you just used wrong path, it should be:
ln -s -f ../../hooks/post-merge .git/hooks/post-merge
While you can use symbolic links, you can also change the hooks folder for your project in your git settings with :
git config core.hooksPath hooks/
Which is local by default so it won't ruin git hooks for your other projects. It works for all hook in this repository, so it's especially useful if you have more than one hook.
If you already have custom hooks in .git/hooks/ that you do not want to share with your team you can add them in hooks/ and add a .gitignore so they're not shared.
Changing directory before linking
cd /path/to/project-repo/.git/hooks
ln -s -f ../../hooks/post-merge ./post-merge
The path calculation is done relative to the symlink. Let's understand using an example,
ln -s path/to/file symlink/file
Here, the path to the file should actually be the relative path from the symlink path.
The system actually calculates the file path as symlink/path/path/to/file
The above command should be re-written as
ln -s ../path/to/file symlink/path
The folder structure being,
/code
------ symlink/file
------ path/to/file
Utilizing Michael Cihar's comment, here is an example of a bash script I wrote to simply create these symlinks. This script is located in git_hooks/ dir which is at the project root. My .git/ folder is also in the same directory level.
#!/usr/bin/env bash
pwd=$(pwd);
# Script is designed to be ran from git_hooks/ dir
if [[ "$pwd" == *"git_hooks"* ]]; then
files=$(ls | grep -v -e '.*\.');
while read -r file; do
ln -s ../../git_hooks/$file ../.git/hooks/
echo "Linked $file -> ../.git/hooks/$file"
done <<< "$files";
else
echo "";
echo "ERROR: ";
echo "You must be within the git_hooks/ dir to run this command";
exit 1;
fi
My script must be ran from within the actual git_hooks/ directory. You can modify it to behave differently, if you'd like.
This script will symlink any file that is not suffixed with a file extension within the git_hooks/ directory. I have a README.txt in this directory + this script (named symlink.sh). All the actual git hooks are named 'pre-commit', 'pre-push', etc. so they will be symlinked.
why not just
cp ./hooks/* .git/hooks/
this worked for me in Mac OS