I am still very new to shell since I have been using it with linux recently, and I tried to mess with a game called garrysmod and make a little script that will ask for information to run the server, its IP, playerslots, etc. Now I somewhat got this working, but I want to be able to save and load this to a config file. I figure out how to get it load from the config, but I want to be able to edit it from the command prompt when it asks you if you would like to edit it.
This is what I have so far as an example:
setup.sh
source config.cfg
echo "Servers current name is $name"
echo
echo "What would you like the name to be?"
read $name
read "The new name is $name"\
config.cfg
name='ServerName'
address=127.0.0.1
port=27015
map='ttt_mapnamehere.bsp'
playercap=32
Now it works after you change it, but I don't know how to get it to save to the .cfg file. The reason of this is because several .sh files will run in order as you go through the steps, and at the end the file one will pull data from the config file being the IP, port, map name, player count, etc. If someone can show me how to do this (examples as Im a visual learner) that would be great!
Simply write it back:
...
printf "name='%s'\naddress='%s'\nport=%s\nmap='%s'\nplayercap=%s\n" \
"$name" "$address" "$port" "$map" "$playercap" > config.cfg
Related
I'm struggling in trying to create a script in Linux (Terminal-Bash) which is automated and when run it will ask for a input and when that input is added it will create sequential files.
See below:
when script is run, it should show
Which country are you from?
I enter Brazil and wish to see:
Data entered: Brazil1, Brazil2, Brazil3.....Brazil 10
The script needs create a batch of 10 each time it is run i.e.
Which country are you from?
I enter Canada and wish to see:
Canada1, Canada2, Canada3.....Canada10
If brazil entered again: Brazil11, Brazil12....Brazil20 and Brazil21, Brazil22....Brazil30 etc
I do not want to hardcode the numbers, automation is required to create them each time.
**Testing:
**
I have created the script by:
Touch test.sh
I have tried to edit the script by:
vim test.sh
In vim I have made the below changes:
#!bin/bash
echo "Which country are you from"
value=country
value{1..10}
Save vim, when executing script I get this message:
test.sh: line 4: value1: command not found
Can someone please help with the script? I'm completely new to linux and trying to best understand how to create the simplest and most effective process.
Thanks in advance.
This script is pretty straightforward to implement. You need to use the read command to read user input in. You can use the while loop with -f to test which files already exist, and then finally the for loop to create those files
#!/bin/bash
echo Hello, what country are you from?
read user_country
n=1
while [ -f "$user_country$n" ]
do
let "n+=10"
done
for ((i=0; i<10; i++))
do
file_num=$((i + n))
touch "$user_country$file_num"
done
There are two releases
1. Dev available at https://example.com/foo/new-package.txt
2. GA available at https://example.com/bar/new-package.txt
I want the user to enter his choice of Dev or GA and based on that need to download the files, in the shell script is there a better way to do it?
There is a file which has environment variables that I'm sourcing inside another script.
env_var.sh
#!/bin/bash
echo "Enter your release"
export release='' #either Dev or GA
This file will be sourced from another script as
download.sh
#!/bin/bash
. ./env_var.sh #sourcing a environment var file
wget https://<Dev or GA URL>/new-package.txt
My main problem is how to set the wget URL based on the release set in env_var file.
Any help is appreciated.
Have you considered using read to get the user input?
read -p 'Selection: ' choice
You could then pass ${choice} to a function that has case statements for the urls:
get_url() {
case $1 in
'dev' ) wget https://example.com/foo/new-package.txt ;;
'ga' ) wget https://example.com/bar/new-package.txt ;;
\? ) echo "Invalid choice" ;;
esac
}
For more information on read, a good reference is TLDP's guide on user input.
Edit: To source a config file, run the command source ${PATH_TO_FILE}. You would then be able to pass the variable to the get_url() function for the same result.
Background
I've a script. It's purpose is to generate config files for various system services from templates whenever my gateway acquires a new IP from my ISP. This process includes making successive edits with sed to replace $[template] strings in my custom templates with the correct information.
And to do that I've created a small function designed to take input from stdin, redirect it to a temporary file passed as an argument, and then move that file to replace the destination (and also, often, source) config file. The "edit-in-place dance", if you will.
I created a simple test script with the problematic function:
#!/bin/bash
inplace_dance() {
read -r -d '' data
printf '%s' "${data}" > "${1}~"
mv "${1}~" "${1}"
}
# ATTN: ls is only being used to generate input for testing. It is not being parsed.
ls -l ~/ | inplace_dance ~/test.out
Unfortunately, this works. So it's not the function itself. I also tried it with my custom logging utility (see "complications" below):
#!/bin/bash
. /usr/local/lib/logging.bash
log_identifier='test'
log_console='on'
inplace_dance() {
read -r -d '' data
printf '%s' "${data}" > "${1}~"
mv "${1}~" "${1}"
}
# ATTN: ls is only being used to generate input for testing. It is not being parsed.
bashlog 'notice' $(ls -l ~/ | inplace_dance '/home/wolferz/test.out')
This also works.
The Problem
In its original context, however, it does not work. I've confirmed that ${data} gets set just fine. And that ${1} contains the correct filename. What fails is the second line of the function. I've confirmed printf is being run (see, "Additional Info - Without The Redirect" below)... but the file its output is being redirected to is never created.
And I've been over the code a dozen-dozen times (not an exaggeration) and have yet to identify the cause. So, in desperation, I'm going to post it here and hope some kind soul will wade through my code and maybe spot the problem that I'm missing. I'd also happily take advice on improvements/replacements to my logging utility (in the hopes of tracking down the problem) or further troubleshooting steps.
Here is the original context. The important lines are 106-110, 136-140, 144-147, and 151-155
Additional Info
☛ PATH/Environment
The PATH is PATH=/usr/local/sbin:/usr/local/bin:/usr/bin. I believe this is being inherited from systemd (systemd=>dhcpcd.service=>dhcpcd=>dhcpcd-run-hooks=>dhcpcd.exit-hook).
dhcpcd-run-hooks (see "Complications" below) does clear the environment (keeping the above PATH) when it runs. Thus, I've added an example of the environment the script runs in to the "original context" gist. In this case, the environment when $reason == 'BOUND'. This is output by printenv | sort at the end of execution (and thus should show the final state of the environment).
NOTE: Be aware this is Arch Linux and the absence of /bin, /sbin, and /usr/sbin in the PATH is normal (they are just symlinks to /usr/bin anyway).
☛ Return Code
Inserting echo $? after the second line of the function gives me a return code of "0". This is true both with the redirect in line 2 and without (just the printf).
☛ Without The Redirect
Without the redirect, in the original context, the second line of the function prints the contents of ${data} to stdout (which is then captured by bashlog()) exactly as expected.
⚠️ Execute Instead of Source.
Turns out that $0 was /usr/lib/dhcpcd/dhcpcd-run-hooks rather than my script. Apparently dhcpcd-run-hooks doesn't execute the script... it sources it. I made some changes to line 196 to fix this.
♔ Aaaaaand that seems to have fixed all problems. ♔
I'm trying to confirm that was the silver bullet now... I didn't notice it was working till I had made several other changes as well. If I can confirm it I'll submit an answer.
Complications
What complicates matters quite a bit is that it's original context is a /etc/dhcpcd.exit-hook script. dhcpcd-run-hooks appears to eat all stderr and stdout which makes troubleshooting... unpleasant. I've implemented my own logging utility to capture the output of commands in the script and pass it to journald but it's not helping in this case. Either no error is being generated or, somehow, the error is not getting captured by my logging utility. The script is running as root and there is no mandatory access control installed so it shouldn't be a permissions issue.
I'm trying to redirect(?) my standard error/output to a text file.
I did my research, but for some reason the online answers are not working for me.
What am I doing wrong?
cd /home/user1/lists/
for dir in $(ls)
do
(
echo | $dir > /root/user1/$dir" "log.txt
) > /root/Desktop/Logs/Update.log
done
I also tried
2> /root/Desktop/Logs/Update.log
1> /root/Desktop/Logs/Update.log
&> /root/Desktop/Logs/Update.log
None of these work for me :(
Help please!
Try this for the basics:
echo hello >> log.txt 2>&1
Could be read as: echo the word hello, redirecting and appending STDOUT to the file log.txt. STDERR (file descriptor 2) is redirected to wherever STDOUT is being pointed. Note that STDOUT is the default and thus there is no "1" in front of the ">>". Works on the current line only.
To redirect and append all output and error of all commands in a script, put this line near the top. It will be in effect for the length of the script instead of doing it on each line:
exec >>log.txt 2>&1
If you are trying to obtain a list of the files in /home/user1/lists, you do not need a loop at all:
ls /home/usr1/lists/ >Update.log
If you are attempting to run every file in the directory as an executable with a newline as its input, and collect the output from all these programs in Update.log, try this:
for file in /home/user1/lists/*; do
echo | "$file"
done >Update.log
(Notice how we avoid the useless use of ls and how there is no redirection inside the loop.)
If you want to create an empty file called *.log.txt for each file in the directory, you would do
for file in /home/user1/lists/*; do
touch "$(basename "$file")"log.txt
done
(Using basename to obtain the file name without the directory part avoids the cd but you could do it the other way around. Generally, we tend to avoid changing the directory in scripts, so that the tool can be run from anywhere and generate output in the current directory.)
If you want to create a file containing a single newline, regardless of whether it already exists or not,
for file in /home/user1/lists/*; do
echo >"$(basename "$file")"log.txt
done
In your original program, you redirect the echo inside the loop, which means that the redirection after done will not receive any output at all, so the created file will be empty.
These are somewhat wild guesses at what you might actually be trying to accomplish, but should hopefully help nudge you slightly in the right direction. (This should properly be a comment, I suppose, but it's way too long and complex.)
Ok, here I'm again, struggling with ssh. I'm trying to retrieve some data from remote log file based on tokens. I'm trying to pass multiple tokens in egrep command via ssh:
IFS=$'\n'
commentsArray=($(ssh $sourceUser#$sourceHost "$(egrep "$v" /$INSTALL_DIR/$PROP_BUNDLE.log)"))
echo ${commentsArray[0]}
echo ${commentsArray[1]}
commax=${#commentsArray[#]}
echo $commax
where $v is something like below but it's length is dynamic. Meaning it can have many file names seperated by pipe.
UserComments/propagateBundle-2013-10-22--07:05:37.jar|UserComments/propagateBundle-2013-10-22--07:03:57.jar
The output which I get is:
oracle#172.18.12.42's password:
bash: UserComments/propagateBundle-2013-10-22--07:03:57.jar/New: No such file or directory
bash: line 1: UserComments/propagateBundle-2013-10-22--07:05:37.jar/nouserinput: No such file or directory
0
Thing worth noting is that my log file data has spaces in it. So, in the code piece I've given, the actual comments which I want to extract start after the jar file name like : UserComments/propagateBundle-2013-10-22--07:03:57.jar/
The actual comments are 'New Life Starts here' but the logs show that we are actually getting it till 'New' and then it breaks at space. I tried giving IFS but of no use. Probably I need to give it on remote but I don't know how should I do that.
Any help?
Your command is trying to run the egrep "$v" /$INSTALL_DIR/$PROP_BUNDLE.log on the local machine, and pass the result of that as the command to run via SSH.
I suspect that you meant for that command to be run on the remote machine. Remove the inner $() to get that to happen (and fix the quoting):
commentsArray=($(ssh $sourceUser#$sourceHost "egrep '$v' '/$INSTALL_DIR/$PROP_BUNDLE.log'"))
You should use fgrep to avoid regex special interpretation from your input:
commentsArray=($(ssh $sourceUser#$sourceHost "$(fgrep "$v" /$INSTALL_DIR/$PROP_BUNDLE.log)"))