Create directory while creating file - macos

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 .

Related

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

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

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.

Shell Script Not Finding File

Hello I am trying to write a simple shell script to use in a cronjob to copy a backup archive of website files to a remote server via FTP.
The script below works when I type the file name in by hand manually, but with the date and filename specified as a variable it returns that it can't find ".tar.gz" as if it is ignoring the first part of the filename.
I would be grateful if someone could tell me where I am going wrong.
#!/bin/sh
NOW=$(date +"%F")
FILE="$NOW_website_files.tar.gz"
# set the local backup dir
cd "/home/localserver/backup_files/"
# login to remote server
ftp -n "**HOST HIDDEN**" <<END
user "**USER HIDDEN**" "**PASSWORD HIDDEN**"
cd "/backup_files"
put $FILE
quit
END
This is because it is looking for a variable name NOW_website_files which does not exist, and thus the resulting file name evaluates to .tar.gz.
To solve it, do:
#!/bin/sh
NOW=$(date +"%F")
FILE="${NOW}_website_files.tar.gz"
^ ^
instead of
FILE="$NOW_website_files.tar.gz"
This way it will concatenate the variable $NEW to the _website_files.tar.gz text.
You could do this:
FILE=$(date +"%F_website_files.tar.gz")
instead of this:
NOW=$(date +"%F")
FILE="$NOW_website_files.tar.gz"
IMPORTANT
By the way, consider adding "bi" to your FTP script as you are clealy PUTting a binary file and you don't want CR/LF translation to occur in binary files...

How to save a string from a file into a variable in bash

I am trying to make a script that will ask you for a path to several files when you set it up and when you run the actual script, it reads the path from a file that you created earlier. I can make the file, I just need to know how to take that path and use it in the current script.
ex.
Settings
/home/user/launcher
Launcher
cat Settings
read PathToLaunchers
cd \$PathToLaunchers
read pathToFiles
for f in $pathToFiles
do
cat $f
done
I am just printing the contexts of each file entered in pathToFiles. You can replace cat command with the command you are interested.
If pathToFiles has only one line (i.e. only one filename), then you dnt need the for loop and just use cat $pathToFiles

Resources