Another Bash permission denied post - linux

I've spent the past hour trying to find a way around this before asking but to no avail so I'm asking.
I am trying to make a simple script that will take the name for a file and then generate a generic blank html template for me.
#!/bin/bash
blank=/home/sithyrys/Documents/scripts/blank.html
echo "Enter file name with no extensions:"
read fileName
fileName+=.html
echo $fileName
touch $fileName
$blank >> $fileName
When I comment out the path the code runs with no error message but then it's not pulling the template and it makes a blank page. The error message in question is:
./basicHTMLTemplate.sh: line 9: /home/sithyrys/Documents/scripts/blank.html: Permission denied
Edit: shebang line copied wrong that was correct already

>> does not copy a file; it appends the output of the command that precedes it to the file named following it. You need to use the cat command to actually "push" the contents of blank.html into the new file.
cat "$blank" >> "$fileName"
As written, your code accommodates the possibility that $fileName already exists and appends the contents of $blank without overwriting the existing file. In practice, it doesn't make much sense to append the template to the end of an existing file, so you probably just want to make a copy of the template.
#!/bin/bash
blank=/home/sithyrys/Documents/scripts/blank.html
echo "Enter file name with no extensions:"
read fileName
fileName+=.html
echo $fileName
cp "$blank" "$fileName"
(or, to guard against overwriting an existing file,
[[ -f "$fileName" ]] || cp "$blank" "$fileName"
)

Related

Bash: "No such file or directory" despite directory existing

I am making a custom command that moves or duplicates a file to a wastebasket directory instead of deleting it. I am trying to make a directory if it already isn't there, make a duplicate if a file has already been executed on, and simply move it if it doesn't. The issue is that I keep getting a no such file or directory error regardless of where I place the wastebasket directory. Do note that simply moving or copying the file with base linux commands work fine, and that being in root doesn't fix the issue. What steps should I take?
#!/bin/bash
set -x
mkdir -p /home/WASTEBASKIT #This makes a wastebasket directory if it doesn't already exist.
if test -e "$1"; then
if test -e /home/WASTEBASKIT/"$1"; then #Checking for duplicate files.
cp "$1" "/home/WASTEBASKIT/$1.$$"
else
mv "$1" "/home/WASTEBASKIT"
fi
else
printf '%s\n' "File not found." #Error if a file is not there.
fi
Here are the results: ++ mkdir -p /home/WASTEBASKIT
++ test -e config.sh
++ test -e /home/WASTEBASKIT/config.sh
++ cp config.sh.945 ' /home/WASTEBASKIT'
cp: cannot stat 'config.sh.945': No such file or directory
cp config.sh.945 ' /home/WASTEBASKIT'
cp: cannot stat 'config.sh.945': No such file or directory
The problem is on this line:
cp "$1" "$1.$$" "/home/WASTEBASKIT"
You try to copy two files into /home/WASTEBASKIT, namely $1 and $1.$$. The latter does not exist.
Change it to:
cp "$1" "/home/WASTEBASKIT/$1.$$"
I suggest that you instead create a unique file since process numbers aren't unique, so instead of the copy above, do something like:
newfile=$(mktemp "WASTEBASKIT/$1.XXXXXXX")
cp -p "$1" "$newfile"
You can then list all the copies with ls -t WASTEBASKIT to get them in historical order, newest first - or with ls -tr WASTEBASKIT to get the oldest first.
Also note: printf'%s\n' "File not found." will likely generate an error like printf%s\n: command not found.... You need to insert a space between the command printf and the argument '%s\n'.
The moving part is also wrong since you have a space before /home. It should be:
mv "$1" /home/WASTEBASKIT
mv "$1" " /home/WASTEBASKIT"
First issue: spaces matter. If you have previously created the /home/WASTEBASKIT directory, and then execute that copy command above, it will not copy the file into that directory - you will most likely end up with a file in your home directory called spaceWASTEBASKIT (unless you already have a directory of that name, including the leading space) in which case it will go into that directory.
Either way, it won't go where you want it to go.
Secondly, the command below is not doing what you seem to think. It will try to copy two files to the directory, the second of which probably does not even exist (config.sh.945 in your case):
cp "$1" "$1.$$" "/home/WASTEBASKIT"
If you want to create a "uniquely" versioned file so as to not overwrite an existing one, that would be:
mv "$1" "/home/WASTEBASKIT/$1.$$"
Note the quotes around the word "uniquely" since there's no guarantee $1.$$ may not also exist in the wastebasket - the PIDs do eventually wrap around at some point, and also do so on reboot.
I suspect a better approach (though still not bullet-proof) would be just to prefix every file with the date and time so that:
you can sort duplicates to establish the order of creation; and
sans date changes, the date/time won't give you possible duplicates (unless you're doing it more then once per second).
That approach would be something like:
mv "$1" "/home/WASTEBASKIT/$(date -u +%Y%m%d_%H%M%S)$1"
or, making duplicates even less likely:
mv "$1" "/home/WASTEBASKIT/$(date -u +%Y%m%d_%H%M%S)_${RANDOM}_$1"

catching user input to run scripts

I am trying to write a small bash script using mac OS TextEdit that will catch a user input in terminal and based on the file type stipulated in the command line albeit (jpg or gif) iterate through a directory on my desktop named dir1, pull all files of that filetype and place such in a new directory called dir2
i.e The user types jpg into the terminal and the script kicks into life and pulls all of the jpg files situated in dir1 and places such in dir2
What is the leanest and least convoluted way of achieving this conscious that I am new to shell scripting.
I am about to reach for the meds. What can I do to the below code to get it to work.
#!/bin/bash
echo “Good Morning, Please enter your file type for sorting [ENTER]:”
read $FILE
if [[ $file == *.jpg ]]; then
mv ~/DIR1/*jpg* ~/Users/christopherdorman/desktop/dir2/
echo “your files have been successfully processed”
fi
There are a couple confusions here regarding bash variables and syntax. You need to use fi to close your if statement instead of done. Also, you need to capitalize the variable in your if statement, since bash is case sensitive. I believe this is what you are looking for (assuming your input is "jpg" or "gif"):
#!/bin/bash
echo “Good Morning, Please enter your file type for sorting [ENTER]:”
read FILE
if [[ $FILE == "jpg" ]]; then
mv ~/DIR1/*jpg* ~/Users/christopherdorman/desktop/dir2/
echo “your files have been successfully processed”
fi

saving output to a file in linux

Script:
#!/bin/bash
mydir="/bamboo/artifacts"
cd "$mydir"
job="-JOB1"
for dir in */
do
bambooplan=`echo $dir | sed 's/\/$//g'`$job
echo $bambooplan
done
Output:
LERST-TSTREDAPIDB2WIN4-JOB1
LERST-TSTREDAPIDB2WIN5-JOB1
CA-TSTALLSQLWIN3-JOB1
CE-CSW-JOB1
CE-SNAP-JOB1
I want to pass this to a file. I tried the commands below and it gives permission denied error. Could someone help me figure what I miss here?
echo $bambooplan > result.txt
$bambooplan > result.txt
I tested your code with the first 'writing line' (echo $bambooplan > result.txt) and worked perfect for me, only i would change echo $bambooplan > result.txt to echo $bambooplan >> result.txt, otherwise, you will overwrite the entire file in each iteration, keeping only the last one.
Be aware that your code writes INSIDE /bamboo/artifacts and you wrote the file path as /bamboo/artifacts, an absolute path, not a relative one -> bamboo/artifacts, so, maybe, you're trying to write in a folder where you don't have writing permissions and need to chmod them.
Redirect just to your defined file by using > as you specified or >> if file already already exists and contains data. Regarding to the permission, just exchange script's rights thru chmod command.
for instance :
chmod 755 scriptname
Same process to change output file's permission.

bash script to replace the name of a zip file

I am very new in programing scripts-.
I have a lot of zip files in a directory. I want to extract them replacing the name of the inside file by the zip file, with the correct extension. Error reporting if there is more than one file, excep if is "remora.txt" inside.
The file "remora.txt" was an ini file for the zip, and I wont use it any more, but is in a lot of my zip files.
Example 1.
ZIp file: maths.zip,
Inside it has:
- "tutorial in maths.doc"
- "remora.txt"
Action:
So the script should erase or deprease "remora.txt" and extract "tutorial in maths.doc" under the name maths.doc
Example 2.
ZIp file: geo.zip,
Inside it has:
- "excersices for geometry.doc"
- "geometry.doc"
- "remora.txt"item
Action:
It should out put "I found more than a file in geo.zip"
I am
Using linux, ubuntu 12
I have done this script, but is not working.
#!/bin/bash
#
# Linux Shell Scripting Tutorial 1.05r3, Summer-2002
#
for archive in *.zip # First I read the zip file
do
((i++))
unzip -Z1 $archive | while read line; # I read all the files in the ZIP
do
line=( ${line//,/ } )
inside[$a]=("${line[#]}") # Here I assigne the name of the file to an array
((a++))
done
If ( $a > 2) then
echo " Too much files in file $archive "
fi
If ($a <= 2)
then
if (inside[0]!= "remora.txt")
then unzip -p $archive > $(printf "%s" $archive).doc
fi
if (inside[1]!= "remora.txt")
then unzip -p $archive > $(printf "%s" $archive).doc
fi
fi
done
Try writing scripts incrementally. Instead of writing 20 statements and then trying to debug them all at once, write one statement at a time and test to make sure it works before writing the next one.
If you run e.g.
If ( $a > 2) then
echo " Too much files in file $archive "
fi
by itself, you'll see that it doesn't work. You then know more specifically what the problem is, and you can look up something like "bash if variable greater than" on Google or Stackoverflow.
Check out the bash tag wiki for more helpful tips on debugging and asking about code.
Things you'll find includes:
if has to be lower case
You need line feed or semicolon before then
To see if a variable is greater than, use [[ $a -gt 2 ]].
To see if an array element does not equal, use [[ ${inside[0]} != "remora.txt" ]]
Pipelines cause subshells. Use while read ...; do ...; done < <(somecommand) instead.

Dynamically rename an XML File in Shell

I have an XML files named as *dmi_standard_load_B0001_set.xml* and I want to rename it dynamically by accepting a *batch_name* from user and change it to *dmi_standard_load_${batch_name}_set.xml*.
How can I do that ? I tried the following command bt it throws error and doesn't work...
mv dmi_standard_load_*_set.xml dmi_standard_load_${batch_name}_set.xml
So what is your typical batch name any spaces in it. If so you may need to put speech marks around the file name the 2nd bit. Worth echo $ batch_name aldo u could try load_$(echo $ $batch_name)_set.xml
Careful! You are using a * wildcard in your command. If you have multiple XML files in your directory, for instance :
dmi_standard_load_B0001_set.xml
dmi_standard_load_B0002_set.xml
dmi_standard_load_B0003_set.xml
your command will expand to this :
mv dmi_standard_load_B0001_set.xml dmi_standard_load_B0002_set.xml dmi_standard_load_B0003_set.xml dmi_standard_load_${batch_name}_set.xml
and most likely, it will fail, telling you that the last argument is not a directory. So the first thing is, you want to loop through your files, like so :
for f in dmi_standard_load_*_set.xml
do
mv ${f} dmi_standard_load_${batch_name}_set.xml
done
DO NOT RUN THAT CODE THOUGH! We're not finished. The problem here is that you're going to rename each of your XML files... to one and only one file. In effect, you'll end up with a file named dmi_standard_load_${batch_name}_set.xml, with the contents of the last XML file that went through the loop.
You want the user to give a different batch name for each of these files, right? So you need to ask her for each file in your loop, with the read command :
for f in dmi_standard_load_*_set.xml
do
echo Please enter a batch name for file $f :
read batch_name
mv ${f} dmi_standard_load_${batch_name}_set.xml
done
This will work, but there is no error checking... the user could just press the Enter key, giving an empty batch name. Here's a final version that makes sure the user gives a name :
for f in dmi_standard_load_*_set.xml
do
batch_name=
while [[ ${batch_name} == '' ]]
do
echo Please enter a batch name for file $f :
read batch_name
done
mv ${f} dmi_standard_load_${batch_name}_set.xml
done
For example you can use this one-line script:
for file_name in *; do echo -ne "Renaming file \"${file_name}\" Enter batch_name: "; read batch_name; mv "${file_name}" "dmi_standard_load_${batch_name}_set.xml"; done
this is example from my gentoo box:
user#host ~/test $ ls -1
dmi_standard_load_B0001_set.xml
dmi_standard_load_B0002_set.xml
dmi_standard_load_B0003_set.xml
dmi_standard_load_B0004_set.xml
dmi_standard_load_B0005_set.xml
user#host ~/test $ for file_name in *; do echo -ne "Renaming file \"${file_name}\" Enter batch_name: "; read batch_name; mv "${file_name}" "dmi_standard_load_${batch_name}_set.xml"; done
Renaming file "dmi_standard_load_B0001_set.xml" Enter batch_name: test
Renaming file "dmi_standard_load_B0002_set.xml" Enter batch_name: another test
Renaming file "dmi_standard_load_B0003_set.xml" Enter batch_name: and test again
Renaming file "dmi_standard_load_B0004_set.xml" Enter batch_name: four
Renaming file "dmi_standard_load_B0005_set.xml" Enter batch_name: last, five
user#host ~/test $ ls -1
dmi_standard_load_and test again_set.xml
dmi_standard_load_another test_set.xml
dmi_standard_load_four_set.xml
dmi_standard_load_last, five_set.xml
dmi_standard_load_test_set.xml
user#host ~/test $

Resources