Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concept: variables #700

Merged
merged 6 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions concepts/commands-and-arguments/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"glennj"
],
"contributors": [
"IsaacG"
"IsaacG",
"kotp"
],
"blurb": "Types of commands; argument splitting; writing scripts."
"blurb": "Bash scripts are written as sequences of commands. Learn about command and arguments, types of commands, and the essentials about writing scripts."
}
2 changes: 1 addition & 1 deletion concepts/commands-and-arguments/about.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Introduction
# About

## Shells

Expand Down
4 changes: 2 additions & 2 deletions concepts/commands-and-arguments/links.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[
{
"description": "Commands and Arguments in the Bash Guide",
"description": "\"Commands and Arguments\" in the Bash Guide",
"url": "https://mywiki.wooledge.org/BashGuide/CommandsAndArguments"
},
{
"description": "Shell Operation in the bash manual",
"description": "\"Shell Operation\" in the bash manual",
"url": "https://www.gnu.org/software/bash/manual/bash.html#Shell-Operation"
}
]
9 changes: 9 additions & 0 deletions concepts/variables/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"authors": [
"glennj"
],
"contributors": [
"IsaacG"
],
"blurb": "Learn about variables in bash, and some of the variable expansions."
}
164 changes: 164 additions & 0 deletions concepts/variables/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# About

## Variables

_Variables_ are a place to hold data.
Bash has two kinds of data: strings and arrays.
We'll talk about arrays later.

You assign a variable like this
```bash
name="value"
```

~~~~exercism/note
**Important** -- there must be _no spaces_ around the equal sign!

When there are spaces, like in this example,

```bash
x = 10
```

bash is going to call the **command** `x` with the **two arguments** `=` and `10`!
~~~~

Variables can also be called _parameters_.
The two terms will be used interchangably in this document.

Some important parameters used by or set by bash include:

* `PATH` -- a colon-separated list of directories used to find external commands.
* `IFS` -- the "internal field separator".
We'll see how it's used below.
* `PWD` -- your current working directory.
It will be the same value as the output of the `pwd` command.
* `RANDOM` -- a pseudo-random integer between 0 and 32767.
* `BASH_VERSION` -- the version string of the running instance of bash.

## Variable Names

A variable name consists of _uppercase letters, lowercase letters, numbers and underscore_.
It cannot start with a number.

~~~~exercism/caution
It is best practice to **avoid using ALLCAPS variable names**.
The shell uses this convention for its parameters, and you don't want to accidentally overwrite shell parameters that have special meaning.
For example: [1][1], [2][2], [3][3]

[1]: https://stackoverflow.com/q/27555060/7552
[2]: https://stackoverflow.com/q/28310594/7552
[3]: https://unix.stackexchange.com/q/114596/4667
~~~~

## Parameter Expansion

You get the value of a parameter with the `$varname` syntax.

```bash
x=10
echo "The value of x is $x"
```

To prevent the variable name from being confused with surrounding text, you can enclose the variable name in braces.
For example to print the string `10x10`

```bash
echo "${x}x$x"
# or
echo "${x}x${x}"
```

Some [style guides][google-style-guide] recommend using braces in most cases for readability and/or consistency.

## Positional Parameters

As we discussed in the [Commands and Arguments][cmds-args] lesson, commands can take arguments.
Bash scripts are no exception.
The arguments to the current instance of bash are called _positional parameters_.
They can be retrieved with these special parameters:

* `$1` -- the first positional parameter
* `$2` ... `$9` -- subsequent parameters
* `${10}` ... -- double digits require braces.
* `$0` -- the name of the current script.

Arguments to a shell function are also positional parameters, handled just like this.
We'll see more about functions in a later lesson.

### Special Positional Parameters

There are some _special parameters_ that help you work with the positional parameters.

* `$#` expands to the _number_ of positional parameters.
* `"$@"` expands to the list of all of the positional parameters, each as a separate word.
* `"$*"` expands to a single string of all the positional parameters joined together by a character.
* The join character is _the first character_ of the `$IFS` variable, which is a space by default.

The `"$@"` is the safest way to pass positional parameters to another command while keeping them safely quoted.
It is also what you will use to loop over the positional parameters:

```bash
for arg in "$@"; do
do_something_with "$arg"
done
```

In practice, `"$@"` is used more often than `"$*"`.

## Command Substitution

A very frequent operation you will do in bash scripts is to capture the output of a command and store it in a variable.
To do this, you will use _command substitution_.

```bash
var=$(command)
```

For example, to upper-case a string, you can do this:

```bash
text="Hello world!"
uppercase=$(echo "$text" | tr '[:lower:]' '[:upper:]')
echo "$uppercase"
# => HELLO WORLD!
```

## More on Parameter Expansion

Bash has many builtin facilities to manipulate variables and strings so that you don't need to call out to external commands.

* Uppercasing text.
In the previous section I showed how to use `tr` to upper case some text.
To do it in bash:

```bash
echo "${text^^}"
```

Similarly, `${text,,}` lowercases the value.

* Provide a default value if the variable is empty.

```bash
default="nothing here"
result=""
echo "${result:-$default}"
# => nothing here
```

* Search and replace.

```bash
text="Hello world!"
echo "${text//[aeiou]/X}"
# => HXllX wXrld!"
```

There are many other interesting parameter expansions: extract a substring, get the string length, _assign_ a default value, remove text from the start or end of the value, and more.
Read about them [in the manual][param-exp].


[google-style-guide]: https://google.github.io/styleguide/shellguide.html
[cmds-args]: https://exercism.org/tracks/bash/concepts/commands-and-arguments
[param-exp]: https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion
164 changes: 164 additions & 0 deletions concepts/variables/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Introduction

## Variables

_Variables_ are a place to hold data.
Bash has two kinds of data: strings and arrays.
We'll talk about arrays later.

You assign a variable like this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You assign a variable like this
You assign a variable (often shortened to var) like this:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it often shortened to var? That's news to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I mean, your next line is varname and not variablename ;) Or you can avoid shortening it in the example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved this by using name="value" for the example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For teaching material, regardless, I do prefer using full names, even if it is often shortened in practice. Those that are not "acronyms and abbreviations as a first language" can then easily look up those words in an English dictionary, making interpretation and deciphering easier (especially on top of mult-language audience/readers being highly likely on this platform).

```bash
name="value"
```

~~~~exercism/note
**Important** -- there must be _no spaces_ around the equal sign!

When there are spaces, like in this example,

```bash
x = 10
```

bash is going to call the **command** `x` with the **two arguments** `=` and `10`!
~~~~

Variables can also be called _parameters_.
The two terms will be used interchangably in this document.

Some important parameters used by or set by bash include:

* `PATH` -- a colon-separated list of directories used to find external commands.
* `IFS` -- the "internal field separator".
We'll see how it's used below.
* `PWD` -- your current working directory.
glennj marked this conversation as resolved.
Show resolved Hide resolved
It will be the same value as the output of the `pwd` command.
* `RANDOM` -- a pseudo-random integer between 0 and 32767.
* `BASH_VERSION` -- the version string of the running instance of bash.

## Variable Names

A variable name consists of _uppercase letters, lowercase letters, numbers and underscore_.
It cannot start with a number.

~~~~exercism/caution
It is best practice to **avoid using ALLCAPS variable names**.
The shell uses this convention for its parameters, and you don't want to accidentally overwrite shell parameters that have special meaning.
For example: [1][1], [2][2], [3][3]

[1]: https://stackoverflow.com/q/27555060/7552
[2]: https://stackoverflow.com/q/28310594/7552
[3]: https://unix.stackexchange.com/q/114596/4667
~~~~

## Parameter Expansion

You get the value of a parameter with the `$varname` syntax.
glennj marked this conversation as resolved.
Show resolved Hide resolved

```bash
x=10
echo "The value of x is $x"
```

To prevent the variable name from being confused with surrounding text, you can enclose the variable name in braces.
For example to print the string `10x10`

```bash
echo "${x}x$x"
# or
echo "${x}x${x}"
```

Some [style guides][google-style-guide] recommend using braces in most cases for readability and/or consistency.

## Positional Parameters

As we discussed in the [Commands and Arguments][cmds-args] lesson, commands can take arguments.
Bash scripts are no exception.
The arguments to the current instance of bash are called _positional parameters_.
They can be retrieved with these special parameters:

* `$1` -- the first positional parameter
* `$2` ... `$9` -- subsequent parameters
* `${10}` ... -- double digits require braces.
* `$0` -- the name of the current script.

Arguments to a shell function are also positional parameters, handled just like this.
We'll see more about functions in a later lesson.

### Special Positional Parameters

There are some _special parameters_ that help you work with the positional parameters.

* `$#` expands to the _number_ of positional parameters.
* `"$@"` expands to the list of all of the positional parameters, each as a separate word.
* `"$*"` expands to a single string of all the positional parameters joined together by a character.
glennj marked this conversation as resolved.
Show resolved Hide resolved
* The join character is _the first character_ of the `$IFS` variable, which is a space by default.

The `"$@"` is the safest way to pass positional parameters to another command while keeping them safely quoted.
It is also what you will use to loop over the positional parameters:

```bash
for arg in "$@"; do
do_something_with "$arg"
done
```

In practice, `"$@"` is used more often than `"$*"`.

## Command Substitution

A very frequent operation you will do in bash scripts is to capture the output of a command and store it in a variable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc mentions "you" a whole lot and things "you will do". I think the prior doc was a little bit less ...directed?

Copy link
Contributor Author

@glennj glennj Aug 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I did lift most of the text from greycat for the last one. Maybe we can "put a pin in it" and revisit it after a few docs are written.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could modify the factoid messages and/or Wooledge wiki, if that helps :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upon reflection, I'll circle back to the first concept to give it a rewrite in my voice.

To do this, you will use _command substitution_.

```bash
var=$(command)
```

For example, to upper-case a string, you can do this:

```bash
text="Hello world!"
uppercase=$(echo "$text" | tr '[:lower:]' '[:upper:]')
echo "$uppercase"
# => HELLO WORLD!
```

## More on Parameter Expansion

Bash has many builtin facilities to manipulate variables and strings so that you don't need to call out to external commands.

* Uppercasing text.
In the previous section I showed how to use `tr` to upper case some text.
To do it in bash:

```bash
echo "${text^^}"
```

Similarly, `${text,,}` lowercases the value.

* Provide a default value if the variable is empty.

```bash
default="nothing here"
result=""
echo "${result:-$default}"
# => nothing here
```

* Search and replace.

```bash
text="Hello world!"
echo "${text//[aeiou]/X}"
# => HXllX wXrld!"
```

There are many other interesting parameter expansions: extract a substring, get the string length, _assign_ a default value, remove text from the start or end of the value, and more.
Read about them [in the manual][param-exp].


[google-style-guide]: https://google.github.io/styleguide/shellguide.html
[cmds-args]: https://exercism.org/tracks/bash/concepts/commands-and-arguments
[param-exp]: https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion
10 changes: 10 additions & 0 deletions concepts/variables/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"description": "\"Parameters\" in the Bash Guide",
"url": "https://mywiki.wooledge.org/BashGuide/Parameters"
},
{
"description": "\"Shell Parameters\" in the bash manual",
"url": "https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameters"
}
]
5 changes: 5 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,11 @@
"uuid": "07e48a7d-7dd0-477c-96e1-23d2558d507d",
"slug": "commands-and-arguments",
"name": "Commands and Arguments"
},
{
"uuid": "e29f24ae-3c3b-479a-9333-d733c1ff8fb4",
"slug": "variables",
"name": "Variables"
}
],
"key_features": [
Expand Down