I'm using command below in my mac machine:
mkdir views && touch views/layout.erb views/home.erb views/about.erb views/contact.erb
It's working as expected. But i'm looking for something, so that i don't have to use directory name(views) to create/touch each file.
You can use bash expansion to make this more concise:
mkdir views && touch views/{layout,home,contact}.erb
You can do something like:
mkdir views && touch views/{layout,home,about,contact}.erb
Or you can change the directory in a sub-shell, so your current shell's working directory is unchanged:
mkdir views && (cd views && touch layout.erb home.erb about.erb contact.erb)
Another option is to use a loop:
mkdir views && for f in layout home about contact ; do touch views/${f}.erb ; done
mkdir views && pushd views && touch layout.erb home.erb about.erb contact.erb && popd
Or:
mkdir views && (cd views && touch layout.erb home.erb about.erb contact.erb)
Related
I'm sure this has been asked but my search has been fruitless.
I want to run 3 bash commands in order with both the second and third only running if the first succeeded.
Example:
## Setup
mkdir so_test_tmp && cd so_test_tmp
echo "This is something" > something
cd ..
## Example commands
cd so_test_tmp ??? cat nothing ??? cd .. # 0.
cd so_test_tmp ??? cat something ??? cd .. # 1.
cd does_not_exist ??? cat nothing ??? cd .. # 2.
These three commands should always end in PWD. In 0. the first cd is run, then the last. In 1. all three commands successfully run. In 2. the first command fails so the second and third are not run.
What about?
pushd .; cmd1 && cmd2 && ... cmdn; popd
pushd . saves your current dir.
Then you execute your commands; you use && so that, if one fails, the others are not executed.
popd goes back to your initial dir.
EDIT: regarding your comment below, yes, this pushd .; popd construct is quite silly; it lets you forget about how the execution of each set of commands went.
pushd .; cd so_test_tmp && cat nothing; popd; # 0.
pushd .; cd so_test_tmp && cat something; popd; # 1.
pushd .; cd does_not_exist && cat nothing; popd; # 2.
You finish at your original dir after running the three sets of commands.
Within each set of commands, whenever a command fails, it shortcuts the execution of the others behind (see they are separated by &&).
If you need to know if each set of commands succeeded or not, you can always test the result of the execution (and go to your initial dir and save it again before running the following set of commands):
pushd .;
cd so_test_tmp && cat nothing && cd .. ; # 0.
test $? -eq 0 || (popd; pushd .) ;
cd so_test_tmp && cat something && cd ..; # 1.
test $? -eq 0 || (popd; pushd .) ;
cd does_not_exist && cat nothing && cd ..; # 2.
test $? -eq 0 || (popd; pushd .) ;
Specifically for cd somewhere && somecommand && cd ..
The cd .. is only necessary because you're doing cd so_test_tmp inside your parent shell, as opposed to the subshell that's fork()ed off to then be replaced with a copy of /bin/cat.
By creating an explicit subshell with ( ... ), you can scope the cd to its contents. By using exec for the last command in the subshell, you can consume it, balancing out the performance overhead of that subshell's creation.
(cd so_test_tmp && exec cat nothing) # 0.
(cd so_test_tmp && exec cat something) # 1.
(cd does_not_exist && exec cat nothing) # 2.
Note that this applies only when the command you're running in a subdirectory doesn't change the state of the shell that started it (like setting a variable). If you need to set a variable, you might instead want something like output=$(cd /to/directory && exec some_command).
Answering the more general question
Use && to connect the first command to a group with the second and third commands, and use ; to combine those 2nd and 3rd commands, if your goal is to ensure that both 2nd and 3rd run if-and-only-if the 1st succeeds.
cd so_test_tmp && { cat nothing; cd ..; } # 0.
cd so_test_tmp && { cat something; cd ..; } # 1.
cd does_not_exist && { cat nothing; cd ..; } # 2.
Setup:
$ cd /tmp
$ mkdir so_test_tmp
$ echo "This is something" > so_test_tmp/something
Wrapping an if/then/fi around OPs current examples:
$ if cd so_test_tmp; then cat nothing; cd ..; fi ; pwd
cat: nothing: No such file or directory
/tmp
$ if cd so_test_tmp; then cat something; cd ..; fi ; pwd
This is something
/tmp
$ if cd does_not_exist; then cat something; cd ..; fi ; pwd
-bash: cd: does_not_exist: No such file or directory
/tmp
This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 3 years ago.
I'm fairly new to bash scripting.
I'm trying to create a directory with a timestamp and then cd into the directory.
I'm able to create a directory and can cd into it the directory with one command.
mkdir "build" && cd "build"
I can create the directory with data then cd into it.
mkdir date '+%m%d%y' && cd date '+%m%d%y' I am able to create this dir and cd into it with one command.
Here is my bash script:
#!/bin/bash
# mkdir $(date +%F) && cd $(date +%F)
mkdir build_`date '+%m%d%y'` && cd build_`date '+%m%d%y'`
I need to create the directory with build_date '+%m%d%y' in the title then cd into that folder.
I've looked online but am unable to come up with a solution.
Thank you.
Try this:
#!/bin/bash
build_dir="build_$(date '+%m%d%y')"
mkdir $build_dir && cd $build_dir
Best is to name your Folders YYYY.MM.DD like build_2019.11.21
#!/bin/bash
DIRECTORY="build_$(date '+%Y.%m.%d')"
if [ ! -d "$DIRECTORY" ]; then
# checking if $DIRECTORY doesn't exist.
mkdir $DIRECTORY
fi
cd $DIRECTORY
touch testfile
Here's a script that uses /usr/bin/env bash and the builtin command printf instead of /bin/date.
#!/usr/bin/env bash
date="$(printf '%(%m%d%y)T' -1)"
[[ -d build_"${date}" ]] || mkdir build_"${date}"
cd build_"${date}"
# do something useful here
# ...
However, changing directory in a script (subshell) is not much use on its own, as your current working directory ($PWD) will be the same after the script exits.
If you want to have the current shell session change into the new directory, use a shell function.
mkbuild() {
date="$(printf '%(%m%d%y)T' -1)"
[[ -d build_"${date}" ]] || mkdir build_"${date}"
cd build_"${date}"
}
Then run it:
$ echo $PWD
/tmp
$ mkbuild
$ echo $PWD
/tmp/build_112119
What is a better way to create sub folders in a shell script? Instead of using the following method?
mkdir /var/log
mkdir /var/log/celery
mkdir /var/log/celery/stdout
mkdir /var/log/celery/stderr
touch /var/log/celery/stdout/stdout.log <<< I'm hoping the use this path create folder if doesn't exists....
touch /var/log/celery/stderr/stderr.log
mkdir has a -p flag that will create parent directories but touch will not create directories that do not exist.
That still cuts the above down to:
mkdir -p /var/log/celery/stdout /var/log/celery/stderr
touch /var/log/celery/stdout/stdout.log /var/log/celery/stderr/stderr.log
Which in a shell that supports brace expansion could even be:
mkdir -p /var/log/celery/{stdout,stderr}
touch /var/log/celery/{stdout/stdout.log,stderr/stderr.log}
And actually, if you have brace expansion but not mkdir -p you could do:
mkdir /var/log{,/celery{,/{stdout,stderr}}}
touch /var/log/celery/{stdout/stdout.log,stderr/stderr.log}
But there isn't any way to combine the mkdir and touch steps with standard tools that I'm aware of.
The -p option of mkdir will create the intermediate folders of the path if they don't exists (and of course, if you have the appropriate privileges):
mkdir -p /var/log/celery/stderr
To create the file, you can append the touch after the operator &&, so the touch operation only occurs if the directory either was created successfully or already exists:
mkdir -p /var/log/celery/stderr && touch "$_/stderr.log"
(Basically, the $_ will pass the dir path to the touch command)
UNTESTED:
$ needir () { mkdir -p $1; echo $1; }
$ touch $(needir /var/log/celery/stderr)/stderr.log
and put "needir" in your .profile, or better yet, in a function library on your path that you source when you login. you'd be surprised how often you'll be using it.
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
I am writing a shell script to run under the KornShell (ksh) on AIX. I would like to use the mkdir command to create a directory. But the directory may already exist, in which case I do not want to do anything. So I want to either test to see that the directory does not exist, or suppress the "File exists" error that mkdir throws when it tries to create an existing directory.
How can I best do this?
Try mkdir -p:
mkdir -p foo
Note that this will also create any intermediate directories that don't exist; for instance,
mkdir -p foo/bar/baz
will create directories foo, foo/bar, and foo/bar/baz if they don't exist.
Some implementation like GNU mkdir include mkdir --parents as a more readable alias, but this is not specified in POSIX/Single Unix Specification and not available on many common platforms like macOS, various BSDs, and various commercial Unixes, so it should be avoided.
If you want an error when parent directories don't exist, and want to create the directory if it doesn't exist, then you can test for the existence of the directory first:
[ -d foo ] || mkdir foo
This should work:
$ mkdir -p dir
or:
if [[ ! -e $dir ]]; then
mkdir $dir
elif [[ ! -d $dir ]]; then
echo "$dir already exists but is not a directory" 1>&2
fi
which will create the directory if it doesn't exist, but warn you if the name of the directory you're trying to create is already in use by something other than a directory.
Use the -p flag.
man mkdir
mkdir -p foo
Defining complex directory trees with one command
mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}
If you don't want to show any error message:
[ -d newdir ] || mkdir newdir
If you want to show your own error message:
[ -d newdir ] && echo "Directory Exists" || mkdir newdir
mkdir foo works even if the directory exists.
To make it work only if the directory named "foo" does not exist, try using the -p flag.
Example:
mkdir -p foo
This will create the directory named "foo" only if it does not exist. :)
The old tried and true
mkdir /tmp/qq >/dev/null 2>&1
will do what you want with none of the race conditions many of the other solutions have.
Sometimes the simplest (and ugliest) solutions are the best.
Simple, silent and deadly:
mkdir -p /my/new/dir >/dev/null 2>&1
You can either use an if statement to check if the directory exists or not. If it does not exits, then create the directory.
dir=/home/dir_name
if [ ! -d $dir ]
then
mkdir $dir
else
echo "Directory exists"
fi
You can directory use mkdir with -p option to create a directory. It will check if the directory is not available it will.
mkdir -p $dir
mkdir -p also allows to create the tree structure of the directory. If you want to create the parent and child directories using same command, can opt mkdir -p
mkdir -p /home/parent_dir /home/parent_dir/child1 /home/parent_dir/child2
mkdir does not support -p switch anymore on Windows 8+ systems.
You can use this:
IF NOT EXIST dir_name MKDIR dir_name
directory_name = "foo"
if [ -d $directory_name ]
then
echo "Directory already exists"
else
mkdir $directory_name
fi
This is a simple function (Bash shell) which lets you create a directory if it doesn't exist.
#------------------------------------------#
# Create a directory if it does not exist. #
#------------------------------------------#
# Note the "-p" option in the mkdir #
# command which creates directories #
# recursively. #
#------------------------------------------#
createDirectory() {
mkdir -p -- "$1"
}
You can call the above function as:
createDirectory "$(mktemp -d dir-example.XXXXX)/fooDir/BarDir"
The above creates fooDir and BarDir if they don't exist. Note the "-p" option in the mkdir command which creates directories recursively.
Referring to man page man mkdir for option -p
-p, --parents
no error if existing, make parent directories as needed
which will create all directories in a given path, if exists throws no error otherwise it creates all directories from left to right in the given path. Try the below command. the directories newdir and anotherdir doesn't exists before issuing this command
Correct Usage
mkdir -p /tmp/newdir/anotherdir
After executing the command you can see newdir and anotherdir created under /tmp. You can issue this command as many times you want, the command always have exit(0). Due to this reason most people use this command in shell scripts before using those actual paths.
Or if you want to check for existence first:
if [[ ! -e /path/to/newdir ]]; then
mkdir /path/to/newdir
fi
-e is the exist test for KornShell.
You can also try googling a KornShell manual.
Improvement on the 'classic' solution (by Brian Campbell) - to handle the case of symlink to a directory.
[ -d foo/. ] || mkdir foo
mkdir -p sam
mkdir = Make Directory
-p = --parents
(no error if existing, make parent directories as needed)
if [ !-d $dirName ];then
if ! mkdir $dirName; then # Shorter version. Shell will complain if you put braces here though
echo "Can't make dir: $dirName"
fi
fi