How to use the directory a shell script is called from? - bash

I am trying to make a script to automate the creation of files and input of certain data in the files, sort of like a template. For example, if the script is called cpp (Just an example, not the actual script name), when I run cpp <filename> it should create a file in the current directory without me having to tell it what the directory is. Right now, I have to hard code a root directory into the script. The basic functionality of the script is something like this (I have validations and stuff, but this is the main function):
touch "$FILE_PATH" (this is the part that I have to hard code)
echo -e "#include <bits/stdc++.h>\n\nusing namespace std;\n\nint main() {\n\t\n}" > "$FILEPATH"
nvim "$FILE_PATH"
In this situation, I have to declare the file path to be FILE_PATH="$HOME/<a specific directory>/$1.cpp", meaning when I call on the script, I have to pass an argument relative to the hard-coded location, like perhaps cpp automation/file_manager/shell/apartment. Is there a way for a shell script to automatically find the directory it is called on, so it can be more dynamic and flexible (Go to the directory automation/file_manager/shell/apartment and call cpp apartment to get the same result)? Kind of like vim or neovim, where it creates a file in the current directory.

You can use
`dirname $0`
in your bash script. This would take the value of the directory where your script is placed. You would be able to execute your bash from anywhere as long as you have the right access.
Good practice:
#initiate the dir name
dir=`dirname $0`
#initiate the name of your file
file="my_filename"
#use as needed:
# create file in current bash directory
touch $dir/$file
# append
echo -e "my_cpp_script" >> $dir/$file
#call
cpp $dir/$file

Related

Shell Command For File To Delete Itself

I want to make a file that runs a script, then deletes itself. I know that its root would most likely be "~/Library/Downloads/filename.app". How would I go about having it self destruct? I'm working in script editor.
I'm not sure if I understand correctly as shell script would traditionally have .sh suffix instead of .app one (if any) and I'm not familiar with anything that I'd call "script editor", but alas here's my solution.
If you are in bash environment, you can make use of the BASH_SOURCE array. Provided that you didn't change the current working directory, you can directly call
rm "${BASH_SOURCE[0]}"
(or just rm "$BASH_SOURCE").
If you are using cd or make larger script, it might be advisable to save fully resolved path to the script at the beginning and remove that file at the end (not somewhere in the middle as running bash scripts are NOT independent on their source files*) like so:
#!/bin/bash
self=$(realpath "${BASH_SOURCE[0]}")
#
# code so ugly I want to delete it when I'm done
#
rm "$self"
*Edit shell script while it's running

Changing PWD in a script to allow for accessing file without prefixing full path

I know I should be able to change the current working directory of a bash script by doing something akin to
cd `dirname $MYPATH`
but for some reason this doesn't work (or not as I imagined it).
#!/bin/bash
WAYPATH="/home/user/articles"
TEST_PATH="/home/user/testing"
# Set working directory of the script to be testing
cd `dirname $TEST_PATH`
for i in $(ls $WAYPATH); do
another_command $i $i.r > $TEST_PATH/htmls/$i.html
done
My goal here is to allow the bash script to find the files located in TEST_PATH (which have matching name to those in WAY_PATH) without having to prefix them with the full path (because another_command) makes use of the whole argument passed to it.
So this is a lesson on understanding what commands do after reading about them on Stackexchange. I was using
cd `dirname $MYPATH`
following this answer where they achieved the desired result
cd `dirname $0`
$0 is the full path of the bash script, so dirname is required to return the path without the name of the file.
Instead, for an arbitrary supplied path is sufficient to do a simple
cd $MYPATH
as suggested in comments.

Parent directory of a script

So I am a rookie in Linux and I need some help. I have to write a bash script in which I have to use the parent directory of the script to create a file there, wherever the script would be. It should look like this:
If my script it's in "/home/student/", I need to create, using an in-script command another file called txt in /home/. Any ideas please? Thank you.
There's a subtlety if you want to be able to run your script from anywhere.
eg: if your script is in /home/myHome/someDir/someOther, and you want to create a file in /home/myHome/someDir wherever you are when you run your script.
To solve it, you just need to first derive the directory where your script is.
It can be done using:
SCRIPT_DIRECTORY="$(dirname "$0")"
touch "$SCRIPT_DIRECTORY/../myFile.txt"
Edit: Actually it can be even more subtle, if you want to handle symlinks. ie: if the symlink /home/myHome/mySymlink points at your script, and is the one actually being called, then the previous script will consider /home/myHome/ instead of /home/myHome/someDir/someOther
To handle this case you can do
if [ -L "$0" ] && [ -x $(which readlink) ]; then
ACTUAL_SCRIPT_FILE="$(readlink -mn "$0")"
else
ACTUAL_SCRIPT_FILE="$0"
fi
SCRIPT_DIRECTORY="$(dirname "$ACTUAL_SCRIPT_FILE")"
touch "$SCRIPT_DIRECTORY/../myFile.txt"
use .. to point to parent directory. So you could create a file using something like
MY_SCRIPTDIR="$(dirname $0)"
touch ${MY_SCRIPTDIR}/../abc.txt
From your command prompt or within shell script.
Unfortunately, the other answers either give you the current working directory instead of the directory the script is in, or they will not work if either the script or one of the directories along the way is a symbolic link rather than a real directory.
What will work is:
dirname $(readlink -f "$0")
Explanation:
"$0" is the name of the script as you type it in your command line. Quoting is important for the case it contains whitespace.
readlink will resolve any symbolic links along the way
dirname takes just the directory name from script's full path - it's better readable and safer for corner cases than manually looking for slashes etc.
Now, you will get the correct result even in a complex case: if your script is in /tmp and you create a symbolic link to it in /tmp/abc/, and your current directory will be /home and you run /tmp/abc/your-script, it will correctly output /tmp, not /home nor /tmp/abc.

Create directory while creating file

I'm brand new to Unix and I'm learning how powerful it can be to run scripts on automating file duplication, etc. I've had help creating the initial script (credit where credit's due: https://apple.stackexchange.com/questions/101436/automate-duplicating-and-renaming-images/101437) but now I'm wondering how to generate a specific directory name while duplicating the files. Here's the original script:
#!/bin/bash
file=$1
prefixes=$2
filename=`basename "$file"`
while read line
do
cp $file "$line-$filename"
done < $prefixes
I basically call the script and then have the prefixes from a text file that's in the same directory append a string to the beginning of the new file that's made. What I would like to do is also create a directory with the original file name so I can then have all the duplicate automatically placed in the new folder. I had tried something like this:
#!/bin/bash
file=$1
prefixes=$2
filename=`basename "$file"`
while read line
do
mkdir $filename
cp $file "$filename/$line-$filename"
done < $prefixes
But that doesn't seem to work. You'll see my intentions though. I would like a directory with the same name as the original file and then have all new images copied into that directory. The command I use in Terminal on Mac OSX is ./copier.sh myimage.jpeg prefixes.txt.
I've gotten the script to create a directory if I just use something like mkdir test but that won't do any good since I'll have to go in and change the directory name every time I run the script.
Let me know if you have any questions. I'm sorry if I'm making some major errors, I'm just having trouble finding the solution to this. Thanks for your help!
If $filename is in the same directory you won't be able to create the directory since a file already exists. You could consider using a different name like the filename without an extension.
#!/bin/bash
file=$1
prefixes=$2
filename=${file##*/} ## Better than using an external binary like basename.
dir=${filename%%.*} ## Remove extension.
mkdir -p "$dir" || exit 1 ## Only need to create it once so place it outside the loop. And `$dir` might already have been made so use `-p`. This would also make the code exit if `mkdir` fails.
while read -r line ## Use -r to read lines in raw form
do
cp "$file" "$dir/$line-$filename"
done < "$prefixes"
Consider quoting your variables properly around "" as well .

Using variables for paths in shell

I want to write a cript for a user to set an installation path.
I am using this
read $file_path
cd $file_path
But it does not change to the path saved on that variable.
How can i set this exactly because this seems the wrong way?
read does not use the $ to read the variable. Hence, it should be
read file_path
cd $file_path
Somewhat reading between the lines, I think you are trying to call a script which you expect to change directory of the caller: For example:
myscript:
read file_path
cd "$file_path"
command-line:
./myscript
and you find it hasn't changed the directory. That's because you are running the script in a child process. It changes the current directory of the child, then returns to the parent, which is unaffected.
You need to source the file instead, that is, run the commands in the current process, not a separate one:
. ./myscript
Yes, notice the extra 'dot' . at the start. This is generically known as the source command, and you can use source instead of 'dot' on bash and csh.

Resources