Creating files with some content with shell script - shell

I need to configure a server with a few files and I want to do it programmatically.
I need to create files say /home/a.config, /var/spool/b.config, /etc/c.config
Files above have some contents (multi lines).
I want to create ONE shell script which can create all three file with multiple lines (around 10).
I would like to know the how can I use CAT command to do that. (inside shell script).
I am looking something like this
echo " going to create /home/a.config"
cat "HOW CAN I HAVE MULTIPLE LINES HERE?? " > /home/a.config
thanks

You can use a here document:
cat <<EOF >filename
first line
second line
third line
EOF
You can place several of these in the same script.

file="/tmp/test.txt"
echo "Adding first line" > $file
echo "Adding first line replaced" > $file
echo "Appending second line " >> $file
echo "Appending third line" >> $file
cat $file
> to add/replace the content ( here actual content got replaced by the 2nd line)
>> to append
Result
Adding first line replaced
Appending second line
Appending third line

Like so:
#!/bin/bash
var="your text"
echo "simply put,
just so: $var" > a.config
For further info, see Input/Output part of abs.
Hope, this helps.

If you've got variables like $1 or $HOMEDIR in your text then these normally get evaluated and substituted with actual values. If you want to prevent these from getting substituted then you need to quote the opening limit string (EOF in example below) with single quote 'EOF', double quote "EOF" or precede it with backslash \EOF
Closing limit string stays as is. EOF
This is especially useful if you are writing shell scripts to a file.
cat << 'EOF' >/etc/rc.d/init.d/startup
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is running with pid: $pid"
else
echo "Tomcat is not running"
fi
;;
esac
EOF
Refer Example 19.7 Parameter Substitution Turned off in Here Documents

>\#!/bin/bash
>
>var="your text" <br>
>echo "simply put, <br>
>just so: $var" > a.config
Note that you also need to escape out certain characters to avoid them interfering with what you're trying to do, for example $ ` and " will all break such a statement unless preceded with a backslash, i.e. \` \$ or \"
so if we define the following:
var="100"
the following would not behave as expected:
echo "simply put,
just "lend" me US$ $var" > a.config
but the following would work correctly:
echo "simply put,
just \"lend\" me US\$ $var" > a.config

Related

Adding new lines to multiple files

I need to add new lines with specific information to one or multiple files at the same time.
I tried to automate this task using the following script:
for i in /apps/data/FILE*
do
echo "nice weather 20190830 friday" >> $i
done
It does the job yet I wish I can automate it more and let the script ask me for to provide the file name and the line I want to add.
I expect the output to be like
enter file name : file01
enter line to add : IWISHIKNOW HOWTODOTHAT
Thank you everyone.
In order to read user input you can use
read user_input_file
read user_input_text
read user_input_line
You can print before the question as you like with echo -n:
echo -n "enter file name : "
read user_input_file
echo -n "enter line to add : "
read user_input_text
echo -n "enter line position : "
read user_input_line
In order to add line at the desired position you can "play" with head and tail
head -n $[$user_input_line - 1] $user_input_file > $new_file
echo $user_input_text >> $new_file
tail -n +$user_input_line $user_input_file >> $new_file
Requiring interactive input is horrible for automation. Make a command which accepts a message and a list of files to append to as command-line arguments instead.
#!/bin/sh
msg="$1"
shift
echo "$msg" | tee -a "$#"
Usage:
scriptname "today is a nice day" file1 file2 file3
The benefits for interactive use are obvious -- you get to use your shell's history mechanism and filename completion (usually bound to tab) but also it's much easier to build more complicated scripts on top of this one further on.
The design to put the message in the first command-line argument is baffling to newcomers, but allows for a very simple overall design where "the other arguments" (zero or more) are the files you want to manipulate. See how grep has this design, and sed, and many many other standard Unix commands.
You can use read statement to prompt for input,
read does make your script generic, but if you wish to automate it then you have to have an accompanying expect script to provide inputs to the read statement.
Instead you can take in arguments to the script which helps you in automation.. No prompting...
#!/usr/bin/env bash
[[ $# -ne 2 ]] && echo "print usage here" && exit 1
file=$1 && shift
con=$1
for i in `ls $file`
do
echo $con >> $i
done
To use:
./script.sh "<filename>" "<content>"
The quotes are important for the content so that the spaces in the content are considered to be part of it. For filenames use quotes so that the shell does not expand them before calling the script.
Example: ./script.sh "file*" "samdhaskdnf asdfjhasdf"

Unix Bash content of a file as argument stops at first line

I'm having an issue in something that seems to be a rookie error, but I can't find a way to find a solution.
I have a bash script : log.sh
which is :
#!/bin/bash
echo $1 >> log_out.txt
And with a file made of filenames (taken from the output of "find" which names is filesnames.txt and contains 53 lines of absolute paths) I try :
./log.sh $(cat filenames.txt)
the only output I have in the log_out.txt is the first line.
I need each line to be processed separately as I need to put them in arguments in a pipeline with 2 softwares.
I checked for :
my lines being terminated with /n
using a simple echo without writing to a file
all the sorts of cat filenames.txt or (< filenames.txt) found on internet
I'm sure it's a very dumb thing, but I can't find why I can't iterate more than one line :(
Thanks
It is because your ./log.sh $(cat filenames.txt) is being treated as one argument.
while IFS= read -r line; do
echo "$line";
done < filenames.txt
Edit according to: https://mywiki.wooledge.org/DontReadLinesWithFor
Edit#2:
To preserve leading and trailing whitespace in the result, set IFS to the null string.
You could simplify more and skip using explicit variable and use the default $REPLY
Source: http://wiki.bash-hackers.org/commands/builtin/read
You need to quote the command substitution. Otherwise $1 will just be the first word in the file.
./log.sh "$(cat filenames.txt)"
You should also quote the variable in the script, otherwise all the newlines will be converted to spaces.
echo "$1" >> log_out.txt
If you want to process each word separately, you can leave out the quotes
./log.sh $(cat filenames.txt)
and then use a loop in the script:
#!/bin/bash
for word in "$#"
do
echo "$word"
done >> log_out.txt
Note that this solution only works correctly when the file has one word per line and there are no wildcards in the words. See mywiki.wooledge.org/DontReadLinesWithFor for why this doesn't generalize to more complex lines.
You can iterate with each line.
#!/bin/bash
for i in $*
do
echo $i >> log_out.txt
done

What is the preferred method to echo a blank line in a shell script?

I am currently writing some code for a shell script that needs a blank line between two parts of the script, as thus they can be separated when output is displayed to the user.
My question is, I am not sure what the preferred practice is in a shell script for a blank line.
Is it preferred practice to just write echo and nothing else or to write echo " " as in echo with quotes and blank between the quotes?
echo is preferred. echo " " outputs an unnecessary space character. echo "" would be better, but it's unnecessary.
but you can use
echo -e "Hi \n"
and print a blank line after Hi, with -e interprets the \n character.
In its first implementation, echo had no option and outputs optional arguments ending with a new line, so it perfectly suit your needs.
For formatted outputs ending with a new line, printf is a better choice, for example : printf "%s\n\n" "output".
All of these commands can be used to echo a blank line:
echo, echo '', echo ""
We cant use echo "\n" or echo '\n' as they will give output as \n in both cases.
printf
More portable and succinct. This prints a hundred lines.
shell
printf '\n%.0s' `seq 1 100`
bash
printf '\n%.0s' {1,100}
As John suggested use echo. However if you want to print a blank line followed by text and anther blank line - as in running a test then use echo -e suggested by wyanzes.
echo -e "\n Now we are going to load data \n"
puts a blank line before and after.

Why the echo failed?

I want to create many new bash scripts through this bash. Here is my code.
#!/bin/bash
# create bash shell automatically
for file in "$*"
do
if [ ! -e "$file" ]
then
touch $file
chmod u+x $file
echo "#!/bin/bash" >> $file
echo "# " >> $file
echo "create success"
fi
done
if [ $# \> 1 ]
then
echo "$# shell files are created!"
else
echo "$# shell is created!"
fi
When I run this script like this:
./create_shell test1 test2 test3
the terminal said:
"line9:ambiguous redirect"
"line10:ambiguous redirect"
What does that mean?
The problem came from the use of $*, whether you quote or unquote it. The correct way to iterate through positional parameter is using "$#", notice the double quote.
for file in "$#"; do
: ...
done
or even POSIXly:
for file do
: ...
done
You got the error message from bash, because bash see the content of $file was not expanded to one word, it was expanded to three separated words test1, test2, test3. Try:
a='1 2 3'
echo 1 >> $a
to see what will happen.
Not to mention that you spoil the sole reason for using "$#". In order for this construct to work, you must also put double quotes around the variables that derive from it, if you don't want the split+glob operators to be invoked. Leaving variables unquote will lead to many security implications.
The '$*' is a string not the parameter array. You can do it like this
fileArr=($*)
for file in ${fileArr[#]}
do you things
The quotes around "$*" will prevent bash from parsing the passed parameter into individual tokens. The loop will be executed once with all of the parameters passed (i.e. if you ran test.sh one two three then the echo command will try to redirect to "one two three"). Just remove the quotes.

Create text file from bash script

I'm playing around with a simpler way to make animated GIFs with captions using gifify (forked from jclem) using ffmpeg and it's captioning library. I tried adding a variable to my script, looking for the optional argument, but I can't even get it to create the temporary .srt file necessary.
Here's my script creating a .txt as proof of concept:
#!/bin/bash
while getopts "t" opt; do
case opt in
t) text=$OPTARG;;
esac
done
shift $(( OPTIND - 1 ))
subtitles=$1
#If there is text present, do this
if [ -z ${text} ]; then
#Make an empty txt file
cat >> /tmp/subs.txt
text=$subtitles
append ${text}
fi
I then run it with:
sh text.sh -t "This is my text"
The script runs and will echo out the string of text you put into the shell, but it won't add it to the new file. Any thoughts on what I'm doing wrong?
!/bin/bash
1) You need case $opt.
while getopts "t:" opt; do
case $opt in
t) text=$OPTARG;;
esac
done
shift $(( OPTIND - 1 ))
subtitles=$1
Then,
if [ -z "$text" ]; then #safer and just as long as the curly bracket version
#Make an empty txt file
: > /tmp/subs.txt #This is how you create an empty file
cat /dev/null > /tmp/subs.txt #A longer version of the same thing
#cat >> /tmp/subs.txt #This APPENDS standard input (STDIN) to /tmp/subs.txt
text="$subtitles"
#append ${text} #`append` isn't bash
echo "$subtitles" > /tmp/subs.txt #the .txt file will contain what's in $subtitles
fi
Edit:
#Etan Reisner makes a good point about the quotation marks.
1) You don't need them in text=$subtitles; bash handles this OK
2) You don't need them in your case in echo $subtitles either--echo works OK with multiple arguments, which is what a bare $subtitles expands to--but you'd better off putting them there too, to make it work for cases like:
a='-e hello\nworld'
echo "$a" #Without the qutoes, $a would get expanded and `-e` would get treated as a flag to `echo`
I thinks it's a good practice to quote variables in bash defensively and not rely on quirks like that in the assignment in 1) or echo's not distinguishing between echo hello world and echo "hello world".
The question is little unclear but here I believe your basic problem is how to create or append a file. Here is the way to create a new file or append it in a shell script. Hopefully this will help. You can use it the way you want ->
Creating a file ->
cat<<EOF>/tmp/subs.txt
${text}
EOF
OR
echo "${text}" >/tmp/subs.txt
Appending a file (note extra '>') ->
cat<<EOF>>/tmp/subs.txt
${text}
EOF
OR
echo "${text}" >>/tmp/subs.txt
The EOF sometimes doesn't work due to tab or white spaces if you dont keep your text left-aligned.
Also regarding "text=$subtitles"; you cannot do that operation after 'cat' so move it before 'cat' command.

Resources