it:ad:bash:home

it:ad:bash

Summary

Basic Linux equivalents of DOS commands:

# make dir
mkdir

#list files
ls

#sort
sort < STUFF

#search
# grep is a command-line utility for searching plain-text data sets for lines that match a regular expression
grep LINE STUFF | sort | uniq

# remove directory
rm 

# help on any command
help mkdir

* no space on either side of = when assigning variables (A=3, not A = 3) * Expansion of variables only occurs within double quotes (not single quotes) * Vars in strings can be $x or ${x}

# figure out where Bash is located by finding out what 
# and you'll get '/bin/bash' back.
# this will inform what to put after the She Bang.

# create an empty file:
touch spike.sh 

# make the file executable:
ch +x spike.sh

# ShBang
The first two lines of the script must be:
<sxh bash>
#! /bin/bash

# invoke it in current directory (so that it doesn't have to go search for it via PATH)
./spike.sh

Like many script languages, it reads the stream from top to bottom, rather than parsing everything before it gets started.

So you have to define your entry points (eg: Main) at the bottom, and probably your first method defined will end being one called Trace

Semi-colons can be used to disambiguate. See how it's sometimes used to put for/next & do on the same line.

for ((i = 0 ; i <= 1000 ; i++));do
...
next

This is Hugely important to decrease your frustration. Bash is OLD. Therefore unforgiving in its parsing.

  • Bash word splits by white spacess, [ and a few other ones. Unless within quotes.
  • When ever it sees a $ followed by a word, it will attempt to replace that token with the referenced value (sometimes referred to as “Parameter Substitution” or “Expanding Variables”).
  • the $ goes to the first “token invalid” symbol. If you need to disambiguate $myVar, you can wrap it in curlies ${myVar} (whether inside or outside of quotes).
  • Double quotes are parsed for variable expansion.
  • Single quotes are literal & left alone, whether there is a $ or not.
  • As single spaces outside of quotes are treated as token delineators you have to REALLY pay attention to how it thinks:
    • h="hello";w="world";
    • r=$h $w # a is assigned to c, terminates at the space, then the processor tries to run the word world (and fails with command not found)
    • r= $h $w # nothing is assigned to c, then it tries to find the command 'hello' (failing) and then the command 'world' (failing again)
    • r =$h $w # r is tried to be executed, but not yet assigned or a commandname (so fails). Then assigns h to nothing. and tries to run the word “world” (fails)
    • r = $h $w # more of the same
    • r="$h $w" # FINALLY WORKS: “hello world” is assigned to c
    • r="${h}ing the${w}" Use curlies to dismabiguate so that it doesn't try to expand 'aing' and it fails
  • Round brackets:
    • ( scope ) # do me first
      • Note: a source of annoyance as ( ) tokens appear similar but are treated as different words/tokens than ((, which is how “math scopes” are defined.
    • $( command ) # expand me
    • (( expression )) # calc me
    • $1) # calc me, then expand me with the result of the calc.
      • This has a place inside of quotes “The count is $2)
      • but fails outside of quotes or assignments as you're asking the processor to execute a command that you're saying is named as a number…
      • [ and ] is a deprecated version of
      • [[ and ]]
        * questions I have:
      • i=10;((i=i+10)) #why does this work (as opposed to using ((i=$i+10)) -- but I guess inside a scope it is expecting tokens only, versus text?)
      • funny enough, whereas usually you have to leave no space before and after =, because it's in an arithmetic scope, as opposed to a command scope it ignores the space.

      * Square brackets:

    • as conditions: (eg: in if statements) [ and ] brackets are the deprecated shorthand for the test command – use [[ and ]] instead.
    • as array indexes:
      • a=(foo bar baz)
      • It appears logical to think one can access arrays as follows $a[*] or $a[1]
        • BUT you need the curly brackets to disambiguate the parser: ${a[*]} and ${a[1]}


        <sxh bash> # works: A=3 # will be 3 B=“Hello World” # will be 'Hello World' C=“$B” # will be 'Hello World' D='$B' # will be '$B'

A =3 # WARN: A= 3 # WARN: A = 3 # WARN: </sxh>

The reason is:

echo "Some text..."

By convention, variables in BASH are UPPERCASE. But lowercase will work fine. Variables are created without $. And then referenced later with $.

FOO="Bar" 

It's an oooold language, so it has primitive ideas.

For one, every variable, whether in a function or not is global by default.

Globals are evil. So it's strongly recommended you local wherever you can.

local X=3

Prompts fill new variables (note, no $).

read -p "So a person walks into a ${FOO} and asks you what is your name: " NAME
read -p "Waiting to Continue..."

Note that variables are disambiguated within strings using ${…}

echo "Hi ${NAME}!"

Logic is implemented using if/elif (not elseif!)/else/fi. Note also that both if AND elif are followed by their own then (but just to shake things up, the final else does not…)

if  ["$NAME" == "Brad"]
  then
    ...
  elif ["$NAME" == "Bob"]
  then
    ...
  else
    ...
# close brackets by reversing the if:
fi 

String comparisons are simpler than equality comparisons:

# string comparison
==
# not equal
!=

Comparisons if IF/ELSE statements will remind you of how [IT/AD/Powershell/] does then:

-eq
-ne
-gt
-ge
-lt
-le

As to when to use == or -eq

Often comparing against text, but also files, which have different comparison operators:

# -e $FILE - True if exists
# -f $FILE - True if file
# -d $FILE - True if directory
# -w $FILE - True if file writable
# -x $FILE - True if file executable
# -u $FILE - True if user id set on file

Which you use as follows:

# Create a Variable (notice, no $)
FILE ="spike.txt"
# Is File Exist?
if [-e "$FILE]
...
fi

Each case clause is terminated with a closing bracket… And the last/default answer is defined as a '*'

case "$ANSWER" in
  # accept upper/lower case "Y" or "YES"
  # Notice the closing, but not opening bracket
  [yY] | [yY][eE][sS])
    echo "Cool"
  [nN] | [nN][oO])
    echo "Not Cool"
  *)
    echo "Please enter Y/YES or N/NO"
esac

for NAME in $NAMES
do
  echo "Hello $NAME"
done

# invoke ls, and get the output:
FILES=$(ls *.txt)
# iterate over it:
for FILE in  $FILES
do 
  echo "Renaming ${FILE} to new-${FILE}"
  mv $FILE NEW-$FILE
done  

LINE=1
while read -r CURRENT_LINE
do 
echo "$LINE: $CURRENT_LINE"
((LINE++))
done < "./theinputfile.txt"

# Actually, no such thing as `for`/`next` -- its `for`+`do`/`done`.
# notice double brackets
# notice ability to put do on same line by semi-colon
# for ((i = 0 ; i <= 1000 ; i++));do
# or:
for ((i = 0 ; i <= 1000 ; i++))
do
  echo "Counter: $i"
done

for outerloop in 1 2 3 4 5
do
  echo -n "Group $outerloop:   "
done

# alternatively:
for i in {0..3}
do
  echo "Number: $i"
done

# stepping:
for i in {0..20..5}
do
  echo "Number: $i"
done

# through arrays:
STUFF=('Foo' 'Bar')

for book in "${STUFF[@]}"; do
  echo "Book: $book"
done

# note note arguments defined in brackets
function FOO() {
  echo "BAR"
}

Parameters are not named – they are positional (reminds me of IT:AD:Perl) starting with $1 (not $0).

# note note arguments defined in brackets
function BAR() {
  # yet they are there.
  echo "FOO $1"
}

You can get all of them (excluding $0, which is the script filename):

$@

You can assign to another argument and shift it (preserving the original array):

$ARGS=$@
#maybe like this:
$ARGS=shift $@ 

You can print all the arguments (for logging) as follows:

echo "$*"

By default all vars are global.

AND Functions don't have Returns.

That doesn't leave many options to program in an productive manner.

One option is to output to stdout and the caller uses command substitution to capture the value in a variable.

function S1(){
  local FOO=3
  # output to stream within execution context
  echo $FOO
}
#Eval the function and capture it's LAST output.
RESULT=$(S1)

But warning: if you have two echo's (eg: debugging to self?) you'll get both…probably not what you were expecting

function S1(){
  local FOO=3
  # output to stream within execution context
  echo "A"
  echo $FOO
}
# Eval the function and capture it's LAST output (but it will be A, then newline then 3... Not what you expected.
RESULT=$(S1)

Due to the above issue, makes sense to know how to redirect echo statements from stdout to stderr:

# redirect stdout (1) to stderr (2):
echo "This Is Error" 1>&2

But definately improved with flags:

Put this on the first line:
if  [[ "debug" == "$1" ]]; then 
   echo "Note: Diagnostics Echoing=ON"
   shift
   DIAGNOSTICS=yes
fi

...

[[ -n "$DIAGNOSTICS" ]] && echo "Debug..." 1>&2
<sxh>

## Piping Output to a File

<sxh bash>
# create file to write to first:
touch "output.txt"
# pipe output:
echo "Foobar" >> "output.txt"

sleep 600

You can printenv or set Environment variables:

USERDOMAIN - domain
USER - The current logged in user.
LOGNAME - The name of the current user.
HOME - The home directory of the current user.
SHELL - The path of the current user’s shell, such as bash or zsh.
PATH - A list of directories to be searched when executing commands. When you run a command the system will search those directories in this order and use the first found executable.
UID - User ID
HOSTNAME: The hostname of the computer at this time.
BASH_VERSION: The version of bash being executed, in human-readable form.
BASH_VERSINFO: The version of bash, in machine-readable output.

exit 0

If a single bracket tells it scope, a double bracket tells it to handle the scope as math:

h
(($SomeVar++))
# or i=$((i+1))
# 1 becomes 2

which is different than

($SomeVar)+($SomeVar) 
# which probably comes out as "1+1"

And

$SomeVar+$SomeVar 
# which probably comes out as "1+1"

# rename files
for file in *.jpeg
do
    mv -- "$file" "${file%.jpeg}.jpg"
done


1)
expression
2)
i++
  • /home/skysigal/public_html/data/pages/it/ad/bash/home.txt
  • Last modified: 2023/11/04 22:20
  • by 127.0.0.1