Understanding and Clarification on AIX and Batch File - linux

I am new to AIX and I have trouble understanding the codes stated in the shell script as shown below, I have a few questions.
if [ "$OutChlName" != "" ] ; then
echo START CHANNEL \($OutChlName\)
fi
For the first line, what does the "" mean, does it mean null?
\($OutChlName\) - is there any way to convert this to a batch file format.
Is it right to say that fi is the end tag of if?
Thank you.

The echo is only wanted when the variable OutChkName is filled.
The string is compared with an empty string.
When you read man test, you can find the alternative if [ -n "$OutChlName" ].
echo with double quotes
Within quotes you do not need the backslashes.
echo "START CHANNEL ($OutChlName)"
My echo behaves different when the OutChlName variable has special characters like newlines or *. I think my syntax is a slight bugfix, but when you do not want to change the original behaviour, you can use
echo "START CHANNEL ("$OutChlName")"
Using backslashes is also a valid syntax (batch format).
fi ends if
Also esac ends case, and done ends do (Odd, it should have been od).

Related

Bash Scripting: Initialzing a path with a text file to a variable & iterating the list in the text file

I'm currently learning the basics of bash scripting (coming from a Pythonic background) and It seems I've run into an interesting situation in which I need a bit of explanation with.
My goal is to create a Path variable that contains a text file. I use an if-statement to check whether the file exists in the directory. If it exists, It will print "It exists".
Then I created a for-loop to print out the elements in the file list. When I execute the program, there is no output and no errors being thrown.
Any help or explanation would be much appreciated! Here is the code below:
#!/bin/bash
veggieFile=/home/lynova/Potato/hewwo.txt
if [ -e veggieFile ]; then
echo "File exists"
for VEGGIE in $(cat veggieFile ); do
echo "Veggies are ${VEGGIE}"
done
fi
You are checking if the file veggieFile exists, not the file whose name is stored in the variable veggieFile. You need to expand the name:
if [ -e "$veggieFile" ]; then
echo "File exists"
while IFS= read -r veggie; do
echo "Veggies are $veggie"
done < "$veggieFile"
fi
See Bash FAQ 001 for more information on why I used a while loop instead of a for loop. Also, all-caps names are reserved; use lower- or mixed-case names for your own variables.
A possible source of confusion might be in how quotes are used. In Python, veggieFile would be a variable whose value is used, while "veggieFile" is a literal string. In shell, though, all strings are literal strings; quotes are only used to escape the contained characters. For example, the quoted word "foo bar" is equivalent to the foo\ bar. You need to use $ to get the value of a variable.

What would cause the BASH error "[: too many arguments" after taking measures for special characters in strings?

I'm writing a simple script to check some repositories updates and, if needed, I'm making new packages from these updates to install new versions of those programs it refers to (in Arch Linux). So I made some testing before executing the real script.
The problem is that I'm getting the error [: excessive number of arguments (but I think the proper translation would be [: too many arguments) from this piece of code:
# Won't work despite the double quoted $r
if [ "$r" == *"irt"* ]; then
echo "TEST"
fi
The code is fixed by adding double square brackets which I did thanks to this SO answer made by #user568458:
# Makes the code works
if [[ "$r" == *"irt"* ]]; then
echo "TEST"
fi
Note that $r is defined by:
# Double quotes should fix it, right? Those special characters/multi-lines
r="$(ls)"
Also note that everything is inside a loop and the loop progress with success. The problems occurs every time the if comparison matches, not printing the "TEST" issued, jumping straight to the next iteration of the loop (no problem: no code exists after this if).
My question is: why would the error happens every time the string matches? By my understanding, the double quotes would suffice to fix it. Also, If I count on double square brackets to fix it, some shells won't recognize it (refers to the answer mentioned above). What's the alternative?
Shell scripting seems a whole new programming paradigm.. I never quite grasp the details and fail to secure a great source for that.
The single bracket is a shell builtin, as opposed to the double bracket which is a shell keyword. The difference is that a builtin behaves like a command: word splitting, file pattern matching, etc. occur when the shell parses the command. If you have files that match the pattern *irt*, say file1irt.txt and file2irt.txt, then when the shell parses the command
[ "$r" = *irt* ]
it expands $r, matches all files matching the pattern *irt*, and eventually sees the command:
[ expansion_of_r = file1irt.txt file2irt.txt ]
which yields an error. No quotes can fix that. In fact, the single bracket form can't handle pattern matching at all.
On the other hand, the double brackets are not handled like commands; Bash will not perform any word splitting nor file pattern matching, so it really sees
[[ "expansion_of_r" = *irt* ]]
In this case, the right hand side is a pattern, so Bash tests whether the left hand side matches that pattern.
For a portable alternative, you can use:
case "$r" in
(*irt*) echo "TEST" ;;
esac
But now you have a horrible anti-pattern here. You're doing:
r=$(ls)
if [[ "$r" = *irt* ]]; then
echo "TEST"
fi
What I understand is that you want to know whether there are files matching the pattern *irt* in the current directory. A portable possibility is:
for f in *irt*; do
if [ -e "$f" ]; then
echo "TEST"
break
fi
done
Since you're checking for files with a certain file name, I'd suggest to use find explicitly. Something like
r="$(find . -name '*irt*' 2> /dev/null)"
if [ ! -z "$r" ]; then
echo "found: $r"
fi

When should I use "" to quote a value in shell test and in echo?

I'm writing bash script like this:
VF_ETH=$(command)
if [ -n "$VF_ETH" ] ; then
echo "ixgbevf eth: "$VF_ETH
fi
command is a linux command, my question is:
$VF_ETH is to get value of VF_ETH, why use "" to quote it in line2 in shell test?
if I do not use "" to quote it, will test failed?
if use "" to quote a value is to make it into string, why not use in echo in line3?
Thank you
Assuming you get an actual command stored in VF_ETH variable, which contains spaces. Now if you use if [ -n $VF_ETH ] and when shell expands the variable, there will be multiple parameters to -n whereas it expects only one. Hence you might get something like binary operator expected error.
Also in the echo command, it is not mandatory to have only one parameter. Hence even if you are not using double quotes, it works.
Hence to avoid it, always use double quotes while expanding variables.
Also use https://www.shellcheck.net/ to check your script and it will give you correct information on where your script is wrong/not as per standard.
You should always double quote variables used in command line arguments and within [ ... ] tests, for example:
ls "$var"
echo "$var"
[ -f "$var" ]
test -f "$var"
In all the above examples the commands used will receive different values with and without the double quotes, when the value of $var starts with a bunch of spaces and contains some spaces. For example:
var=" an apple"
echo "$var" # prints " an apple"
echo $var # prints "an apple", without the leading space
You don't need to quote them in simple assignments, for example:
a=$var
a=$var$b
If the assignment contains spaces or other special characters, then you have to quote, or escape those special characters:
a="$var $b"
a=$var\ $b
a=$var" "$b
All the above are equivalent, but the first one is probably the easiest to read, and therefore recommended.
You don't need to quote special variables that never have unsafe values, for example:
test $? = 0
If you're unsure, or not yet confident, then a good role of thumb is to double quote always.
For 1. and 2. If you set $VF_ETH="x -a -z x" and test it with code:
if [ -n $VF_ETH ] ; then
echo yes
else
echo nope
fi
the output will be nope as the the inside of the square brackets would expand to -n x AND -z x (nonempty and empty). Adding quotes around the variable would fix that.
Set $VF_ETH="*". Now if you echo $foo bash would do wildcard expansion and echo would output the contents of your current directory.

Save one line of echo to variable in BASH?

Okay the answer to this may be really simple but I have been searching for a while and I can't figure it out. I have a variable called "tmessagef". The variable is formatted like:
value1*value2*vlaue3*value4*value5
The only part of the variable I want is value 5. I am currently using the following code but it only prints each value and doesn't save them to a variable:
OIFS=$IFS
IFS='*'
arr2=$tmessagef
for x in $arr2
do
echo "$x"
done
IFS=$OIFS
What I want to do is get the 5th line that the echo command produces and save that to a variable called "tmessage". How would I go about doing this?
Thanks in advance.
Array manipulation:
OIFS="$IFS" IFS='*' Y=($X)
x=${Y[${#Y[#]}-1]}
IFS="$OIFS"
For this very specific scenario (where you only want to extract the value at the very end), you can use parameter expansion
echo "${word##*\*}"
or assign it to a variable instead of using "echo".
Explanation:
## removes the longest substring anchored at the beginning that matches the pattern
* matches any number of any character
\* matches a literal asterisk
So basically, remove the longest substring that ends with an asterisk.
I believe mcalex's comment should answer it:
Change echo "$x" to tmessage="$x". At the end of the loop $val will contain the last value
IFS=* read -r _{,,,} tmessage _ <<<"$tmessagef"
or
[[ $tmessagef =~ ^(.*\*){4}(.*)\* ]]; tmessage=${BASH_REMATCH[2]}
Read http://mywiki.wooledge.org/BashFAQ/001 and the trillion other answers to this question.
Don't use echo for this. If you have output that needs saving, see: http://mywiki.wooledge.org/BashFAQ/002
Can you use cut?
VAL=`echo 'value1*value2*vlaue3*value4*value5' | cut -f5 -d'*'`

Adding newline characters to unix shell variables

I have a variable in a shell script in which I'd like to format the data. The variable stores new data during every iteration of a loop. Each time the new data is stored, I'd like to insert a new line character. Here is how I'm trying to store the data into the variable.
VARIABLE="$VARIABLE '\n' SomeData"
Unfortunately, the output includes the literal '\n' Any help would be appreciative.
Try $'\n':
VAR=a
VAR="$VAR"$'\n'b
echo "$VAR"
gives me
a
b
A common technique is:
nl='
'
VARIABLE="PreviousData"
VARIABLE="$VARIABLE${nl}SomeData"
echo "$VARIABLE"
PreviousData
SomeData
Also common, to prevent inadvertently having your string start with a newline:
VARIABLE="$VARIABLE${VARIABLE:+$nl}SomeData"
(The expression ${VARIABLE:+$nl} will expand to a newline if and only if VARIABLE is set and non-empty.)
VAR="one"
VAR="$VAR.\n.two"
echo -e $VAR
Output:
one.
.two
Other than $'\n' you can use printf also like this:
VARIABLE="Foo Bar"
VARIABLE=$(printf "${VARIABLE}\nSomeData")
echo "$VARIABLE"
OUTPUT:
Foo Bar
SomeData
I had a problem with all the other solutions: when using a # followed by SPACE (quite common when writing in Markdown) both would get split onto a new line.
So, another way of doing it would involve using single quotes so that the "\n" get rendered.
FOO=$'# Markdown Title #\n'
BAR=$'Be *brave* and **bold**.'
FOOBAR="$FOO$BAR"
echo "$FOOBAR"
Output:
# Markdown Title #
Be *brave* and **bold**.
Single quote All special characters between these quotes lose their
special meaning.https://www.tutorialspoint.com/unix/unix-quoting-mechanisms.htm
So the syntax you use does something different that you want to achieve.
This is what you need:
The $'\X' construct makes the -e option in echo unnecessary.
https://linux.die.net/abs-guide/escapingsection.html
echo -e "something\nsomething"
or
echo "something"$'\n'"something"
It's a lot simpler than you think:
VARIABLE="$VARIABLE
SomeData"
Building upon the first two solutions, I'd do like shown below. Concatenating strings with the '+=' operator, somehow looks clearer to me.
Also rememeber to use printf as opposed to echo, you will save yourself so much trouble
sometext="This is the first line"
sometext+=$'\n\n'
sometext+="This is the second line AFTER the inserted new lines"
printf '%s' "${sometext}"
Outputs:
This is the first line
This is the third line AFTER the inserted new line
Your problem is in the echo command, in ash you have to use the option -e to expand special characters. This should work for you:
VAR="First line"
VAR="$VAR\nSecond line"
echo -e $VAR
This outputs
First line
Second line

Resources