Shell scripts: Data to template text-file - bash

I would like to create a script that takes some text-data, and produces a text-file according to a pre-created template file.
The expected functioning would be something like follows: I have created a template text file
Today we describe <text1>.
<text2>
Hope you enjoyed the topic of today!
and I would like to automatically create files with specified data <text1> and <text2> as input. I imagine the usage would be the most convenient if I could just save <text1> and <text2> as the first and second line of a text document. So assume I have created the file input.txt with just two lines (or some other separator than a line-break if it is better):
flowers
Flowers form a subset of plants. They are often beautiful.
Then I would like that running sh description.sh would produce me a file flowers.txt with the content
Today we describe flowers.
Flowers form a subset of plants. They are often beautiful.
Hope you enjoyed the topic of today!
So the question is, what should be the content of description.sh to function like this?
I am new in doing shell scripts, so probably I am not able to search with correct key words to find out if such a thing is easy or is answered here already many times. I also appreciate explanations together with the correct line of code, to learn more. Sorry and thanks for your help!

This will do what you intend. It will generate a file called 'result.txt'.
Be careful with your input as you might need to escape for sed to work as expected.
execute.sh :
#!/bin/bash
[[ "$#" -ne 2 ]] && { echo "This command requires two parameters. A dictionary and a template. Example : ./execute.sh dict.txt template.txt"; exit 1;}
dict=$1 && shift
template=$1 && shift
tmpfile="$(mktemp /tmp/executor_XXXXXXXXXXX)"
declare -a words
cntr=1
while read line
do
words[cntr]="$line"
(( cntr++ ))
done <<< "$( cat input.txt )"
cat "$template" > "$tmpfile"
for((i=1; i <= "${#words[#]}" ; i++ ))
do
sed -i "s/<$i>/${words[$i]}/g" "$tmpfile"
done
cat "$tmpfile" > result.txt
usage :
./execute.sh input.txt template.txt
Also, I changed your templating logic so you need to type <1> instead of <text1> as it requires less typing.

Related

Bash Script IF statement not functioning

I am currently testing a simple dictionary attack using bash scripts. I have encoded my password "Snake" with sha256sum by simply typing the following command:
echo -n Snake | sha256sum
This produced the following:
aaa73ac7721342eac5212f15feb2d5f7631e28222d8b79ffa835def1b81ff620 *-
I then copy pasted the hashed string into the program, but the script is not doing what is intended to do. The script is (Note that I have created a test dictionary text file which only contains 6 lines):
echo "Enter:"
read value
cat dict.txt | while read line1
do
atax=$(echo -n "$line1" | sha256sum)
if [[ "$atax" == "$value" ]];
then
echo "Cracked: $line1"
exit 1
fi
echo "Trying: $line1"
done
Result:
Trying: Dog
Trying: Cat
Trying: Rabbit
Trying: Hamster
Trying: Goldfish
Trying: Snake
The code should display "Cracked: Snake" and terminate, when it compares the hashed string with the word "Snake". Where am I going wrong?
EDIT: The bug was indeed the DOS lines in my textfile. I made a unix file and the checksums matched. Thanks everyone.
One problem is that, as pakistanprogrammerclub points out, you're never initializing name (as opposed to line1).
Another problem is that sha256sum does not just print out the checksum, but also *- (meaning "I read the file from standard input in binary mode").
I'm not sure if there's a clean way to get just the checksum — probably there is, but I can't find it — but you can at least write something like this:
atax=$(echo -n "$name" | sha256sum | sed 's/ .*//')
(using sed to strip off everything from the space onwards).
couple issues - the variable name is not set anywhere - do you mean value? Also better form to use redirection instead of cat
while read ...; do ... done <dict.txt
Variables set by a while loop in a pipeline are not available in the parent shell not the other way around as I mistakenly said before - it's not an issue here though
Could be a cut n paste error - add an echo after the first read
echo "value \"$value\""
also after atax is set
echo "line1 \"$line1\" atax \"$atax\""

Create multiple files in Unix using a script

I am new to unix and I am starting to get my head around it slowly. I would like to know how I can create multiple files within an folder in my directory.
Untill now I was doing it manually one by one. I was using the following code:
echo 'random text here' > newfile1.txt
I would like to create a script that will do the following:
new file x n
newfile1.txt newfile2.txt newfile3.txt newfilen.txt
I would like to have some dummy text inside the files to. I am learning vim and bash.
Thank You
Here is another possibility:
for i in file{1..3}; do printf "random text\n" > $i; done
zsh also allows the more simpler:
printf "random text\n" > random_text{1..3}
One way:
seq 3 | awk '{print "random text" > "newfile"i++".txt"}' i=1
In place of 3, put the value of n.
#!/bin/bash
for n in `seq 1 10`; do
echo "$3" > $1/$2$n.txt
done
This script takes in 3 command line arguments, the first is the already created folder you want the files created in, the second is the first part of the filename, the third is dummy text you want inserted. :)
./script.sh my_folder basename dummytext
(provided as a bash answer)
A classic for loop would be good.
This is just for fun. (don't use in your script)
yes "foo text"|head -10|awk '{print >"newFile"NR".txt"}'
Sometimes we should use yes command, to show that we don't forget him, or he is gonna be sad. :-)

Use first 3 characters of a filename as a variable in shell script

this is my first post so hopefully I will make my question clear.
I am new to shell scripts and my task with this one is to add a new value to every line of a csv file. The value that needs added is based on the first 3 digits of the filename.
I bit of background. The csv files I am receiving are eventually being loaded into partitioned oracle tables. The start of the file name (e.g. BATTESTFILE.txt) contains the partitioned site so I need to write a script that takes the first 3 characters of the filename (in this example BAT) and add this to the end of each line of the file.
The closest I have got so far is when I stripped the code to the bare basics of what I need to do:
build_files()
{
OLDFILE=${filename[#]}.txt
NEWFILE=${filename[#]}.NEW.txt
ABSOLUTE='path/scripts/'
FULLOLD=$ABSOLUTE$OLDFILE
FULLNEW=$ABSOLUTE$NEWFILE
sed -e s/$/",${j}"/ "${FULLOLD}" > "${FULLNEW}"
}
set -A site 'BAT'
set -A filename 'BATTESTFILE'
for j in ${site[#]}; do
for i in ${filename[#]}; do
build_files ${j}
done
done
Here I have set up an array site as there will be 6 'sites' and this will make it easy to add additionals sits to the code as the files come through to me. The same is to be siad for the filename array.
This codes works, but it isn't as automated as I need. One of my most recent attempts has been below:
build_files()
{
OLDFILE=${filename[#]}.txt
NEWFILE=${filename[#]}.NEW.txt
ABSOLUTE='/app/dss/dsssis/sis/scripts/'
FULLOLD=$ABSOLUTE$OLDFILE
FULLNEW=$ABSOLUTE$NEWFILE
sed -e s/$/",${j}"/ "${FULLOLD}" > "${FULLNEW}"
}
set -A site 'BAT'
set -A filename 'BATTESTFILE'
for j in ${site[#]}; do
for i in ${filename[#]}; do
trust=echo "$filename" | cut -c1-3
echo "$trust"
if ["$trust" = 'BAT']; then
${j} = 'BAT'
fi
build_files ${j}
done
done
I found the code trust=echo "$filename" | cut -c1-3 through another question on StackOverflow as I was researching, but it doesn't seem to work for me. I added in the echo to test what trust was holding, but it was empty.
I am getting 2 errors back:
Line 17 - BATTESTFILE: not found
Line 19 - test: ] missing
Sorry for the long winded questions. Hopefully It contains helpful info and shows the steps I have taken. Any questions, comment away. Any help or guidance is very much appreciated. Thanks.
When you are new with shells, try avoiding arrays.
In an if statement use spaces before and after the [ and ] characters.
Get used to surrounding your shell variables with {} like ${trust}
I do not know how you fill your array, when the array is hardcoded, try te replace with
SITE=file1
SITE="${SITE} file2"
And you must tell unix you want to have the rightside eveluated with $(..) (better than backtics):
trust=$(echo "${filename}" | cut -c1-3)
Some guidelines and syntax help can be found at Google
Just use shell parameter expansion:
$ var=abcdefg
$ echo "${var:0:3}"
abc
Assuming you're using a reasonably capable shell like bash or ksh, for example
Just in case it is useful for anyone else now or in the future, I got my code to work as desired by using the below. Thanks Walter A below for his answer to my main problem of getting the first 3 characters from the filename and using them as a variable.
This gave me the desired output of taking the first 3 characters of the filename, and adding them to the end of each line in my csv file.
## Get the current Directory and file name, create a new file name
build_files()
{
OLDFILE=${i}.txt
NEWFILE=${i}.NEW.txt
ABSOLUTE='/app/dss/dsssis/sis/scripts/'
FULLOLD=$ABSOLUTE$OLDFILE
FULLNEW=$ABSOLUTE$NEWFILE
## Take the 3 characters from the filename and
## add them onto the end of each line in the csv file.
sed -e s/$/";${j}"/ "${FULLOLD}" > "${FULLNEW}"
}
## Loop to take the first 3 characters from the file names held in
## an array to be added into the new file above
set -A filename 'BATTESTFILE'
for i in ${filename[#]}; do
trust=$(echo "${i}" | cut -c1-3)
echo "${trust}"
j="${trust}"
echo "${i} ${j}"
build_files ${i} ${j}
done
Hope this is useful for someone else.

Extracting the strings between the patterns and storing it in different files using Shell Script

I am new to unix shell scripting. My goal is to extract a set of strings present between the lines "--------" and store each set of strings to different files.
Eg:
My file main.txt looks like
----------------------------
One
two
three
----------------------------
abc
four
five
-----------------------------
Expected Output:
String appearing in between the lines "----" has to be stored in different files like,
first.txt contains,
one
two
three
Second.txt contains,
abc
four
five
Request your valuable help in this.
Thanks in advance,
Srikanth
i=0; file=$i.txt; cat tmp/t.txt |while read line;
do if [ "$line" = "----------------------------" ];
then let "i=i+1"; file=$i.txt; continue;
fi;
echo "$line" >> $file;
done
BTW, I use the shell only for interactive work. All coding gets done in Python.
You could use awk, too. But then you could use Python, Ruby, .... too.

Bourne Shell Scripting -- simple for loop syntax

I'm not entirely new to programming, but I'm not exactly experienced. I want to write small shell script for practice.
Here's what I have so far:
#!/bin/sh
name=$0
links=$3
owner=$4
if [ $# -ne 1 ]
then
echo "Usage: $0 <directory>"
exit 1
fi
if [ ! -e $1 ]
then
echo "$1 not found"
exit 1
elif [ -d $1 ]
then
echo "Name\t\tLinks\t\tOwner\t\tDate"
echo "$name\t$links\t$owner\t$date"
exit 0
fi
Basically what I'm trying to do is have the script go through all of the files in a specified directory and then display the name of each file with the amount of links it has, its owner, and the date it was created. What would be the syntax for displaying the date of creation or at least the date of last modification of the file?
Another thing is, what is the syntax for creating a for loop? From what I understand I would have to write something like for $1 in $1 ($1 being all of the files in the directory the user typed in correct?) and then go through checking each file and displaying the information for each one. How would I start and end the for loop (what is the syntax for this?).
As you can see I'm not very familiar bourne shell programming. If you have any helpful websites or have a better way of approaching this please show me!
Syntax for a for loop:
for var in list
do
echo $var
done
for example:
for var in *
do
echo $var
done
What you might want to consider however is something like this:
ls -l | while read perms links owner group size date1 date2 time filename
do
echo $filename
done
which splits the output of ls -l into fields on-the-fly so you don't need to do any splitting yourself.
The field-splitting is controlled by the shell-variable IFS, which by default contains a space, tab and newline. If you change this in a shell script, remember to change it back. Thus by changing the value of IFS you can, for example, parse CSV files by setting this to a comma. this example reads three fields from a CSV and spits out the 2nd and 3rd only (it's effectively the shell equivalent of cut -d, -f2,3 inputfile.csv)
oldifs=$IFS
IFS=","
while read field1 field2 field3
do
echo $field2 $field3
done < inputfile.csv
IFS=oldifs
(note: you don't need to revert IFS, but I generally do to make sure that further text processing in a script isn't affected after I'm done with it).
Plenty of documentation out the on both for and while loops; just google for it :-)
$1 is the first positional parameter, so $3 is the third and $4 is the fourth. They have nothing to do with the directory (or its files) the script was started from. If your script was started using this, for example:
./script.sh apple banana cherry date elderberry
then the variable $1 would equal "apple" and so on. The special parameter $# is the count of positional parameters, which in this case would be five.
The name of the script is contained in $0 and $* and $# are arrays that contain all the positional parameters which behave differently depending on whether they appear in quotes.
You can refer to the positional parameters using a substring-style index:
${#:2:1}
would give "banana" using the example above. And:
${#: -1}
or
${#:$#}
would give the last ("elderberry"). Note that the space before the minus sign is required in this context.
You might want to look at Advanced Bash-Scripting Guide. It has a section that explains loops.
I suggest to use find with the option -printf "%P\t%n\t%u\t%t"
for x in "$#"; do
echo "$x"
done
The "$#" protects any whitespace in supplied file names. Obviously, do your real work in place of "echo $x", which isn't doing much. But $# is all the junk supplied on the command line to your script.
But also, your script bails out if $# is not equal to 1, but you're apparently fully expecting up to 4 arguments (hence the $4 you reference in the early part of your script).
assuming you have GNU find on your system
find /path -type f -printf "filename: %f | hardlinks: %n| owner: %u | time: %TH %Tb %TY\n"

Resources