Bash Variable Not Being Assigned - bash

I have this bash script, that gets an input from the user, and returns a phonetic transcription of the word, even if no transcription is available. However, the variable results isn't being assigned as a blank line is being printed instead of the value inside.
I have tried putting the commands into a different script, and that also produced blank lines, and doubled checked that there was no space between results and =
Code:
#!/usr/bin/env bash
#check if user entered a word to translate to ipa
#if a word was not entered prompt the user to enter a word
#else set the word passed as an argument to the variable current
if [ -z "$1" ]
then
echo "You did not enter a word for translation, Please enter one now: "
read current
else
current=$1
fi
#confirm to user the word they entered
echo "The word you chose for translation: $current"
#format the word into '< w o r d >'
onmt_word=$(python ONMT_DATA_FORMAT.py "$current")
#write over current word in temp_word.txt
echo $onmt_word > temp_word.txt
#translate the word in temp_word.txt using openNMT with the model created from a set of 32k words
results=$(onmt_translate -gpu -1 -model eng_ipa_model1_steps/eng_ipa_model1_step_100000.pt -src temp_word.txt -replace_unk -verbose -output model1_step_10000_temp_pred)
#print only the results we care about, i.e. the translated IPA
echo "The provided IPA translation is:"
echo $results | egrep -o '< .* >'
echo "Please ignore the first and last symbol, these are needed for the translation process."
Source:
https://github.com/LonelyRider-cs/LING4100_project

Related

How do I obtain regex matches of piped command using shell script?

First of all I'm trying to obtain a certain property from a KML file. For now, I tried
ogrinfo C:/test.kml -so -al | findstr "Extent"
which was recommended to me and outputs
Extent: (-100.054053, 33.702234) - (-94.647180, 37.125712)
I would require this in the form
-100.054053,-94.647180,33.702234,37.125712 for which I thought to use regex.
I tried the following just to see what it outputted:
ogrinfo C:/test.kml -so -al | findstr "Extent" | findstr /r /c:"-*[0-9]*\.[0-9]*"
but this still outputs
Extent: (-100.054053, 33.702234) - (-94.647180, 37.125712)
I read somewhere that Windows' FINDSTR only outputs the line where it matched and not the regex matches themselves. Is there some other way of doing it?
If I get that working I would save the matches in different variables somehow in a shell script. I'm no expert in shell scripting but I've been looking around and was thinking of doing something like this
#!/bin/bash
for /f "tokens=*" %%a in ('ogrinfo C:/test.kml -so -al ^| findstr "Extent" ^| findstr /r /c:"-*[0-9]*\.[0-9]*"') do (
echo %%a
#do something
)
done >output
but running this causes the shell to immediately disappears and can't even see the error.
Assumptions
You have a kml file with raw data.
You can extract a single line which starts with "Extent: " to get the values you want
Single line => there is only 1 line with that format in the kml file
The format of that line is:
Extent: (NUMBER1, NUMBER2) - (NUMBER3, NUMBER4)
A number can have the following characters: 0 1 2 3 4 5 6 7 8 9 . -
The output you want is:
NUMBER1,NUMBER3,NUMBER2,NUMBER4
Using Linux tools only, you can do this:
#!/bin/bash
#
datafile="data.kml"
# Ensure the data file exists
if [[ ! -f "$datafile" ]]
then
echo "ERROR: the data file does not exist."
exit 1
fi
# Extract the "Extent:" line
dataline=$(grep "Extent: " "$datafile")
# Make sure the line is of a valid format, and assign the number variables
if [[ $dataline =~ "Extent: ("([0-9.-]+)", "([0-9.-]+)") - ("([0-9.-]+)", "([0-9.-]+)")" ]] && number1="${BASH_REMATCH[1]}" && number2="${BASH_REMATCH[2]}" && number3="${BASH_REMATCH[3]}" && number4="${BASH_REMATCH[4]}"
then
echo "-----DEBUG-----"
echo "line==$dataline"
echo "1==$number1"
echo "2==$number2"
echo "3==$number3"
echo "4==$number4"
echo "-- END DEBUG --"
echo ""
echo "$number1,$number3,$number2,$number4"
else
echo "ERROR: there is no \"Extent: \" line in the data file ($datafile)"
fi
Details:
Everything is done in the if line.
=~ matches the left side with the pattern on the right side.
In the regular expression, you can define sections you want to reuse with ( ).
Ex: abcd(1)efgh(2)ijkl. The sections you can reuse are 1 and 2.
So in the if, each number is surrounded by parentheses.
When the =~ is processed, the BASH_REMATCH array is defined with each section.
The "DEBUG" echo statements can be removed or commented out.
If you have more than one "Extent: ..." in the KML file, you can loop on the lines and process each one at a time.

What & How does this line of code work: {message:0:1} {message:23:17}

Would love for someone to help educate me on this line of code.
using diff command to compare two files which somehow allows for other commands such as message:0:1 and message:23:17 to access it's results.
How does this work?
message=$(diff previousscan.txt scan.txt | grep 192)
#get first char which indicates if the host came up or went away
iostring="${message:0:1}"
#get first ip-number from the list
computer="${message:23:17}"
#show ip-number in notify if host came up
if [ "$iostring" = \> ]; then
notify-send "$computer online"
fi
#show ip-number in notify if host went away
if [ "$iostring" = \< ]; then
notify-send "$computer offline"
fi
$message is not a command; it is a variable which holds the output of the diff command. The later lines reference substrings; ${message:0:1} is the first character (1 character starting at offset 0) of whatever is stored in $message.
A simple example to show the substring mechanism:
$ message="abcdefghijklmnop"
$ echo ${message:0:1}
a
$ echo ${message:7:3}
hij
The construction foo=$(bar) runs the command bar in a subshell, and places the output you would normally see in your terminal if you simply ran the command bar in the variable $foo.

How can I edit a .conf file easily?

So I read the easiest way to use .conf files for bash scripts is to use source to load such files. Now, what if I want to edit this file ?
Some code I found does a really good job :
function set_config(){
sed -i "s/^\($1\s*=\s*\).*\$/\1$2/" $conf_file
}
But, if the variable is not yet defined, it doesn't define it, nor does it check if the parameters are passed well, isn't secure, doesn't handle default values etc...
Does reliable tools/code already exists to edit .conf file which contain key="value" pairs ? For instance, I would like to be able to do things like this :
$conf_file="my_script.conf"
conf_load $conf_file #should create the file if it doesn't exist !
read=$(conf_get_value "data" "default_value") #should read the value with key "data", defaulting to "default_value"
if [[ $? = 0 ]] #we should be able to know if the read was successful
then
echo "Successfully read value for field \"data\" : $read"
else
echo "Default value for field \"data\" : $read"
fi
conf_set "something_new" "a great value!" #should add the key "something_new" as it doesn't exist
conf_set "data" "new_value" #should edit the value with key "data"
if [[ $? = 0 ]]
then
echo "Edit successful !"
else #something went wrong :-/
echo "Edit failed !"
fi
before running this code, the conf file would contain
data="some_value"
and after it would be
data="new_value"
something_new="a great value!"
and the code should output
Successfully read value for field "data" : some_value
Edit successful !
I am using bash version 4.3.30 .
Thanks for your help.
I'd to that with awk since it's rather good at tokenizing:
# overwrite config's entries for KEY with VALUE or else appends the definition
# Usage: set_config KEY VALUE
set_config() {
[ -n "$1" ] && awk -F= -v key="$1" -v new="$1=\"$2\"" '
$1 == key { $0 = new; key_found = 1; }
{ print }
END { if (!key_found) { print new; }
' "$conf_file" > "$conf_file.new" \
&& cat "$conf_file.new" > "$conf_file" && rm "$conf_file.new"
}
If run without arguments, set_config() will do nothing and return false. If run with only one argument, it will create an empty value (outputting KEY="").
The awk command parses the .conf file line by line, looking for each definition of the given key and altering it to the new value. All lines are then printed (with or without modification), preserving the original order. If the key hasn't yet been found by the end of the file, this appends the new definition.
Because you can't pipe a file atop itself, this gets saved with a ".new" extension and then copied atop the original in a manner that preserves permissions. The ".new" copy is then removed. I used && to ensure that these never happen if an error occurred earlier in the function.
Also note that the type of ".conf file" you're referring to (the type you source with a POSIX shell) will never have spaces around its equals signs, so the \s* parts of your sed command aren't needed.

Randomize the echo char in Highline's ask method?

I am trying to randomize the echo character in the Highline gem's ask method, but could not get it to work. Did I not do this right?
srand
ask("password: ") { |q| q.echo = ('a'.ord+rand(26)).chr }
The character is randomized for each ask() call, but not each character. The first run will echo the same character, i.e. 'cccc'. The next run will echo 'mmmm', etc.
echo is a variable value used to determine whether to echo output. From the highline source:
# [echo] Can be set to +true+ or +false+ to control whether or not input will
# be echoed back to the user. A setting of +true+ will cause echo to
# match input, but any other true value will be treated as a String to
# echo for each character typed.
Your code (('a'.ord+rand(26)).chr) is being evaluated once per ask, stored in the echo variable within highline, and then printed out for each character entered.
You can't get it to print a different random character per input character without modifying highline.

How to print and edit variable content at the same place on runtime of a Unix shell script?

I have been looking all around (with no avail) to perform the following:
I want to display and able to edit if necessary the content of a variable in runtime for a Unix shell script after giving it a value. The idea goes like this:
Suppose we have a variable value either defined in script or by user input
var=12345
Print the variable value, but also leave the cursor in that position of printing and either press just enter to leave it intact or enter a new value in runtime
Edit variable content (press Enter to leave intact) : 12345
at this point at runtime, I want to leave the cursor in the position of number 1, while showing the variable, and working in the way that if I press Enter, leave the original content (12345) or read for a new value in that same place and modify. Clearing the display of the variable when typing anything else than Enter would be a big plus.
I have looked all around for a way to do this, but just haven't found anything. Anyone willing to provide a solution?
I would suggest you doing this in another way:
var=12345
echo "Change the value of Var (current value: $var)"
read -p "New value (Press Enter to skip):" nvar
if [[ "$nvar" != "" ]]; then
var="$nvar"
fi
echo $var
with this, it will prompt:
Change the value of Var (current value: 12345)
New value (Press Enter to skip):
what you wanted in the question (without the "big plus" part), could be achieved too:
var=12345
echo -ne "Now you may want to change the value: \n$var\r"
read nvar
if [[ "$nvar" != "" ]]; then
var="$nvar"
fi
echo $var
with this, it will prompt (cursor sits between ** )
Now you may want to change the value:
*1*2345
With bash, you could use the readline option for read, but that does not put the cursor at the beginning. It does however do what you want
var=12345
read -ep "Enter new value: " -i $var var
If you need the cursor to go back, you can do this:
var=12345
prompt="Enter new value: $var"
for ((i=1; i<=${#var}; i++)); do prompt+=$'\b'; done
read -p "$prompt" new
[[ -z $new ]] && new=$var

Resources