What's the order of execution of commands in bash? - bash

I've made a little command that is supposed to cd me to subdirectory with the name of current date, and if such directory doesn't exist, firstly creates one:
cd $(date +%F) || (mkdir $(date +%F); cd $(date +%F);)
It works correctly with pre-existing directory, but when directory doesn't exist it creates the directory but doesn't cd :
luk45s5#DESKTOP:~/test$ ls
luk45s5#DESKTOP:~/test$ cd $(date +%F) || (mkdir $(date +%F); cd $(date +%F);)
-bash: cd: 2020-04-04: No such file or directory
luk45s5#DESKTOP:~/test$ ls
2020-04-04
What's the problem, how do I fix it? I'm using Ubuntu WSL if that's any help.

What's the problem, how do I fix it?
If cd fails it will execute the next command which is mkdir and cd but because of the subshell after the script/commands exit you will be in the same directory where you started the script/commands.
You can use a loop.
until cd "$(date +%F)" 2>/dev/null; do
mkdir -p "$(date +%F)"
done
In your example you can use command grouping using the { }
cd $(date +%F) 2>/dev/null || { mkdir $(date +%F) && cd $(date +%F) ; }
2>/dev/null redirects the error message to /dev/null

Related

File not adding in zip by bash script but work in command line in terminal

I am running a script in cron and trying to add a file in a zip by below code,
#!/bin/bash
cd /home/mainfolder/cron
date=$(date --date=yesterday +%F)
FILE=/home/mainfolder/folder/$date.zip
if test -f "$FILE"; then
echo $date
else
wget -r -np -nH --user=USER --password=PASSWORD https://sercret-website.com/$date.zip -P /home/mainfolder/folder/
zip -ur $date.zip file.txt
mkdir temp
cp /home/mainfolder/folder/$date.zip /home/mainfolder/temp/
cd /home/mainfolder/temp/
fi
my file name is yesterday date lets say today is 2019-12-18 (yyyy-mm-dd) my file name is 2019-12-17.zip
when I run in bash sh -x script.sh it didn't work
when i run normally in terminal it work well
zip -ur 2019-12-17.zip file.txt
I am using CentOS server.
Anyone know what I am doing wrong.
I tries
#!/bin/sh != #!/bin/bash
#!/bin/sh
#!/bin/bash
nothing work
I'd change date=$(date --date=yesterday +%F) to:
date=`date --date=yesterday +%F`
and write zip as
zip -ur ${date}.zip file.txt
and shebang as:
#!/bin/sh -x
Then I'd look for reason of failure in cron log files.

trying to create a script with timestamp [duplicate]

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

How to "cd" to a directory which is created using "mkdir $(date '+%d-%b-%Y')"

mkdir $(date '+%d-%b-%Y')
then cd to the dynamically created directory
How to "cd" to a directory which is created using "mkdir $(date '+%d-%b-%Y')" and do the operations by moving into the created directory in bash script
Simple way would be, you store the directory name in a variable
dirname=$(date '+%d-%b-%Y')
if [ -n "$dirname" ]; then
mkdir "$dirname"
if [ -d "$dirname" ]; then
cd "$dirname"
fi
fi
Added some error handling and also if your file is written in Windows and being run in an unix environment or vice-versa, I would recommend using dos2unix which will handle the new line character conversions (this is for the ? characters OP is seeing in ls).
Can you show me your case?
In most cases, you should not cd in to the directory. Use absolute path instead:
Good practice:
mkdir /tmp/mydir/
cp -R /usr/local/example/ /tmp/mydir/
sed 's/foo/bar/g' /tmp/mydir/afile
Bad practice:
mkdir /tmp/mydir/
cd /tmp/mydir/
cp -R /usr/local/example/ .
sed 's/foor/bar/g' afile
P.S.
Subj:
$ mkdir $(date '+%d-%b-%Y')
$ cd $(date '+%d-%b-%Y')
$ pwd
/Users/user/18-Feb-2019
In Bash, $_ expands to the last argument to the previous command. So you could do:
mkdir $(date '+%d-%b-%Y')
cd $_
In a real Bash program you would want to quote the expansions (use Shellcheck on your code to check for missing quotes), and check for errors on both mkdir and cd.

Symlink dotfiles with a script

As many others have done, I want to create a repo to store my dotfile customizations. Instead of doing ln -s manually, I am using the following script to set things up.
#!/bin/bash
set -e
DIR="$HOME/Documents/Dotfiles"
OLDDIR="$HOME/Documents/Other\ Files/Dotfiles_old"
FILES=($HOME/.bash_profile)
echo "Creating $OLDDIR for backup of any existing dotfiles in ~"
mkdir -p "$OLDDIR"
echo "…done"
echo "Changing to the $DIR directory"
cd "$DIR"
echo "…done"
for FILE in "${FILES[#]}"; do
echo "Backup dotfile $FILE from ~/ to $OLDDIR"
cp -L "$HOME/$FILE" "$OLDDIR"
done
for FILE in "${FILES[#]}"; do
echo "copy $FILE from ~ to $DIR."
cp -L "$HOME/$FILE $DIR/"
echo "Creating symlink to $FILE from ~ to $DIR."
ln -sfn "$DIR/$FILE" "$HOME/$FILE";
done
shellcheck source "$HOME/.bash_profile"
When I run this, cp fails because it thinks that .bash_profile isn't there, which obviously isn't the case:
I think my path to the files may be incorrect, although shellcheck reports nothing. What am I forgetting here?
UPDATE: Made another run at this - minus the cp. The one thing I am still unsure of is the use of exit, in particular since I'm already using -e to check for errors.
Shellcheck and bash -n return 0.
#!/bin/bash
set -e
function makeFiles() {
touch .bash_profile \
touch .gitconfig \
touch .gitignore_global
}
function makeLinks() {
ln -sfn ~/Documents/Dotfiles/.bash_profile ~/.bash_profile \
ln -sfn ~/Documents/Dotfiles/.gitconfig ~/.gitconfig \
ln -sfn ~/Documents/Dotfiles/.gitignore_global ~/.gitignore_global \
source ~/.bash_profile
}
read -rp "This may overwrite existing files. Are you sure? (y/n) " -n 1;
echo "";
if [[ $REPLY =~ ^[Yy]$ ]]; then
makeFiles && makeLinks
fi;
Sigh, ln decides that .bash_profile needs to be a directory for some crazy reason.
You're building the path of the dotfile incorrectly - $FILE already contains the full path of the dotfile, and there's no need to prepend $HOME again. Try with this cp command:
cp -L "$FILE $DIR/"

BASH redirect create folder

How can I have the following command
echo "something" > "$f"
where $f will be something like folder/file.txt create the folder folder if does not exist?
If I can't do that, how can I have a script duplicate all folders (without contents) in directory 'a' to directory 'b'?
e.g if I have
a/f1/
a/f2/
a/f3/
I want to have
b/f1/
b/f2/
b/f3/
The other answers here are using the external command dirname. This can be done without calling an external utility.
mkdir -p "${f%/*}"
You can also check if the directory already exists, but this not really required with mkdir -p:
mydir="${f%/*}"
[[ -d $mydir ]] || mkdir -p "$mydir"
echo "something" | install -D /dev/stdin $f
try
mkdir -p `dirname $f` && echo "something" > $f
You can use mkdir -p to create the folder before writing to the file:
mkdir -p "$(dirname $f)"

Resources