Linux CLI 54 🐧 shell script variables
my_variable="Hello, World!"
echo $my_variable
unset my_variable
echo $my_variable
#!/bin/bash
# Declare and initialize variables
greeting="Hello, World!"
name=$1
age=30
# Accessing variables
echo $greeting
echo "Name: $name"
echo "Age: $age"
# Using special variables
echo "Script name: $0"
echo "Number of arguments: $#"
echo "All arguments as a single word: $*"
echo "All arguments as separate words: $@"
echo "Process ID: $$"
echo "Exit status of last command: $?"
Variables are the foundation of any shell script. They let you store values, pass data around, and make your scripts flexible instead of hardcoded. Shell scripts also come with a set of special variables that the shell fills in automatically — the script name, arguments, process ID, and exit status.
Key point: In shell scripting, variables are untyped — they hold strings by default, and the shell decides how to interpret them based on context. There are no spaces around the = when assigning, and you use $ to read a variable’s value.
a – variables
Variables are used to store and manipulate data. In shell scripting, a variable is just a name that points to a value.
Declaring variables:
Assign a value using =:
my_variable="Hello, World!"
Rules:
| Rule | Example |
|---|---|
No spaces around = | VAR="value" ✅ — VAR = "value" ❌ |
| Names can have letters, digits, underscores | my_var, var2, _tmp |
| Names can’t start with a digit | 2var ❌ — var2 ✅ |
| Names are case-sensitive | Var and var are different |
| Values can be quoted or unquoted | VAR=hello or VAR="hello world" |
Accessing variables:
Use $ before the name:
echo $my_variable
echo ${my_variable}
The ${...} form is safer — it avoids ambiguity when the variable name runs into adjacent text:
$ name="Kronos"
$ echo "Hello, $name!"
Hello, Kronos!
$ echo "Hello, ${name}!"
Hello, Kronos!
# Without braces, this fails:
$ echo "$name_file" # looks for $name_file — empty!
$ echo "${name}_file" # correct: Kronos_file
Quoting matters:
$ greeting="Hello, World!"
$ echo $greeting
Hello, World!
# Same result here because there's no glob or extra whitespace
$ echo "$greeting"
Hello, World!
# But quoting protects against word splitting and globbing:
$ files="*.txt"
$ echo $files # expands the glob!
[ file1.txt file2.txt ]
$ echo "$files" # literal: *.txt
[ *.txt ]
Best practice: Always quote your variables —
"$VAR"— unless you specifically want word splitting or globbing.
Unsetting variables:
$ my_variable="Hello, World!"
$ echo $my_variable
[ Hello, World! ]
$ unset my_variable
$ echo $my_variable
[ ]
Using variables in scripts and on the command line:
# On the command line
$ name="Kronos"
$ echo "Hello, $name"
[ Hello, Kronos ]
# In a script
$ cat > greet.sh << 'EOF'
#!/bin/bash
name="Kronos"
echo "Hello, $name"
EOF
$ chmod +x greet.sh
$ ./greet.sh
[ Hello, Kronos ]
Note: Variables set in a script are local to that script — they don’t persist after the script exits. Variables set on the command line persist in that shell session only.
Assigning from commands (command substitution):
# Use $(...) to capture command output
$ TODAY=$(date +%F)
$ echo "Today is $TODAY"
[ Today is 2024-01-15 ]
$ FILES=$(ls *.txt)
$ echo "Text files: $FILES"
[ Text files: file1.txt file2.txt ]
$ HOSTNAME_SHORT=$(hostname -s)
$ echo "Host: $HOSTNAME_SHORT"
[ Host: olympos ]
Assigning from user input:
$ read -p "What is your name? " name
What is your name? Kronos
$ echo "Hello, $name!"
[ Hello, Kronos! ]
Arithmetic:
$ a=5
$ b=3
$ sum=$((a + b))
$ echo $sum
[ 8 ]
$ ((a++))
$ echo $a
[ 6 ]
Variable scope:
| Scope | How |
|---|---|
| Local to shell session | VAR=value |
| Exported to child processes | export VAR=value |
| Local to a function | local VAR=value |
| Read-only | readonly VAR=value |
# Export to child processes
$ export EDITOR="nano"
$ bash -c 'echo $EDITOR'
[ nano ]
# Local to a function
$ myfunc() {
local tmp="secret"
echo "$tmp"
}
$ myfunc
[ secret ]
$ echo "$tmp"
[ ]
Common built-in variables:
| Variable | Meaning |
|---|---|
HOME | Home directory |
USER | Current user |
PATH | Command search path |
PWD | Current directory |
SHELL | Current shell |
LANG | Locale |
EDITOR | Default editor |
Examples of variable assignment and use:
# Simple string
$ greeting="Hello, World!"
$ echo "$greeting"
[ Hello, World! ]
# Number
$ count=42
$ echo "Count: $count"
[ Count: 42 ]
# From a command
$ uptime_info=$(uptime -p)
$ echo "$uptime_info"
[ up 3 days, 4 hours, 22 minutes ]
# From an argument
$ echo "First arg: $1"
[ First arg: hello ]
# Arithmetic
$ x=10
$ y=20
$ echo "Sum: $((x + y))"
[ Sum: 30 ]
# Default value
$ echo "${UNSET:-default}"
[ default ]
# Length of a value
$ name="Kronos"
$ echo "Length: ${#name}"
[ Length: 6 ]
# Substring
$ echo "${name:0:3}"
[ Kro ]
# Uppercase
$ echo "${name^^}"
[ KRONOS ]
# Lowercase
$ echo "${name,,}"
[ kronos ]
b – special variables
Shell scripts have several special variables that are automatically set by the shell. You don’t assign them — they’re provided for you.
| Variable | Meaning |
|---|---|
$0 | The name of the script |
$1 – $9 | Positional parameters passed to the script |
${10}, ${11}, … | Positional parameters past 9 (need braces) |
$# | Number of positional parameters |
$* | All positional parameters as a single word |
$@ | All positional parameters as separate words |
$$ | Process ID of the current script |
$? | Exit status of the last command executed |
$! | PID of the last background command |
$- | Current shell options/flags |
Examples:
$ cat > args.sh << 'EOF'
#!/bin/bash
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "Number of arguments: $#"
echo "All args (single word): $*"
echo "All args (separate words): $@"
echo "Process ID: $$"
EOF
$ chmod +x args.sh
$ ./args.sh hello world foo
[ Script name: ./args.sh ]
[ First argument: hello ]
[ Second argument: world ]
[ Number of arguments: 3 ]
[ All args (single word): hello world foo ]
[ All args (separate words): hello world foo ]
[ Process ID: 12345 ]
$* vs $@ — the crucial difference:
At first glance they look the same. But when quoted, they behave differently:
#!/bin/bash
echo "With \$*:"
for arg in "$*"; do
echo " [ $arg ]"
done
echo "With \$@:"
for arg in "$@"; do
echo " [ $arg ]"
done
$ ./test.sh one two three
With $*:
[ one two three ]
With $@:
[ one ]
[ two ]
[ three ]
| Form | Quoted | Result |
|---|---|---|
$* | "$*" | All args as one string |
$@ | "$@" | Each arg as a separate string |
$* | unquoted | Word-split |
$@ | unquoted | Word-split |
Rule of thumb: Use
"$@"almost always — it preserves argument boundaries and handles spaces correctly.
$? — exit status:
$ ls /etc/passwd
[ /etc/passwd ]
$ echo $?
[ 0 ]
$ ls /nonexistent
[ ls: cannot access '/nonexistent': No such file or directory ]
$ echo $?
[ 2 ]
| Exit code | Meaning |
|---|---|
0 | Success |
1 | General error |
2 | Misuse of shell builtin |
126 | Command found but not executable |
127 | Command not found |
128+N | Killed by signal N |
130 | Interrupted by Ctrl+C |
Using $? in scripts:
#!/bin/bash
if [ $? -eq 0 ]; then
echo "Last command succeeded"
else
echo "Last command failed"
fi
# Better: check the command directly
if ls /etc/passwd > /dev/null 2>&1; then
echo "File exists"
else
echo "File not found"
fi
$$ — process ID:
#!/bin/bash
echo "This script is running as PID $$"
# Useful for unique temp files
TMPFILE="/tmp/myscript-$$.tmp"
echo "Using temp file: $TMPFILE"
$! — last background PID:
$ sleep 100 &
[ 1 ] 12345
$ echo $!
[ 12345 ]
$ kill $!
$0 — script name:
#!/bin/bash
echo "You ran: $0"
# Common idiom: use $0 in usage messages
if [ -z "$1" ]; then
echo "Usage: $0 <filename>"
exit 1
fi
A complete example — a script that uses all the special variables:
#!/bin/bash
echo "=== Script Info ==="
echo "Script name: $0"
echo "Process ID: $$"
echo "Number of args: $#"
echo
echo "=== Arguments ==="
echo "All args (as one word): $*"
echo "All args (separate): $@"
echo
echo "=== Individual Arguments ==="
for i in "$@"; do
echo " [ $i ]"
done
echo
echo "=== Exit Status ==="
ls /etc/passwd > /dev/null
echo "ls exit status: $?"
ls /nonexistent > /dev/null 2>&1
echo "ls (bad) exit status: $?"
$ ./info.sh alpha beta gamma
=== Script Info ===
[ Script name: ./info.sh ]
[ Process ID: 12345 ]
[ Number of args: 3 ]
=== Arguments ===
[ All args (as one word): alpha beta gamma ]
[ All args (separate): alpha beta gamma ]
=== Individual Arguments ===
[ alpha ]
[ beta ]
[ gamma ]
=== Exit Status ===
[ ls exit status: 0 ]
[ ls (bad) exit status: 2 ]
Complete Example Session
# ============================================
# PART 1: BASIC VARIABLES ON THE COMMAND LINE
# ============================================
$ my_variable="Hello, World!"
$ echo $my_variable
[ Hello, World! ]
$ unset my_variable
$ echo $my_variable
[ ]
# ============================================
# PART 2: A SCRIPT WITH VARIABLES
# ============================================
$ cat > vars.sh << 'EOF'
#!/bin/bash
# Declare and initialize variables
greeting="Hello, World!"
name=$1
age=30
# Accessing variables
echo $greeting
echo "Name: $name"
echo "Age: $age"
# Using special variables
echo "Script name: $0"
echo "Number of arguments: $#"
echo "All arguments as a single word: $*"
echo "All arguments as separate words: $@"
echo "Process ID: $$"
echo "Exit status of last command: $?"
EOF
$ chmod +x vars.sh
$ ./vars.sh Alice
[ Hello, World! ]
[ Name: Alice ]
[ Age: 30 ]
[ Script name: ./vars.sh ]
[ Number of arguments: 1 ]
[ All arguments as a single word: Alice ]
[ All arguments as separate words: Alice ]
[ Process ID: 12345 ]
[ Exit status of last command: 0 ]
# ============================================
# PART 3: QUOTING MATTERS
# ============================================
$ name="Kronos"
$ echo "Hello, $name!"
[ Hello, Kronos! ]
$ echo "Hello, ${name}!"
[ Hello, Kronos! ]
# Braces needed when adjacent to other characters
$ echo "${name}_file"
[ Kronos_file ]
$ echo "$name_file"
[ ]
# ============================================
# PART 4: COMMAND SUBSTITUTION
# ============================================
$ TODAY=$(date +%F)
$ echo "Today is $TODAY"
[ Today is 2024-01-15 ]
$ UPTIME=$(uptime -p)
$ echo "$UPTIME"
[ up 3 days, 4 hours, 22 minutes ]
# ============================================
# PART 5: USER INPUT
# ============================================
$ read -p "Your name: " username
Your name: Alice
$ echo "Hello, $username"
[ Hello, Alice ]
# ============================================
# PART 6: ARITHMETIC
# ============================================
$ a=5
$ b=3
$ echo $((a + b))
[ 8 ]
$ echo $((a * b))
[ 15 ]
$ echo $((a - b))
[ 2 ]
$ echo $((a / b))
[ 1 ]
# ============================================
# PART 7: SPECIAL VARIABLES
# ============================================
$ cat > special.sh << 'EOF'
#!/bin/bash
echo "Script: $0"
echo "First arg: $1"
echo "Second arg: $2"
echo "Count: $#"
echo "PID: $$"
echo "Last status: $?"
EOF
$ chmod +x special.sh
$ ./special.sh one two
[ Script: ./special.sh ]
[ First arg: one ]
[ Second arg: two ]
[ Count: 2 ]
[ PID: 12345 ]
[ Last status: 0 ]
# ============================================
# PART 8: $* VS $@
# ============================================
$ cat > star.sh << 'EOF'
#!/bin/bash
echo "With \$*:"
for arg in "$*"; do
echo " [ $arg ]"
done
echo "With \$@:"
for arg in "$@"; do
echo " [ $arg ]"
done
EOF
$ chmod +x star.sh
$ ./star.sh one two three
With $*:
[ one two three ]
With $@:
[ one ]
[ two ]
[ three ]
# ============================================
# PART 9: EXIT STATUS
# ============================================
$ ls /etc/passwd > /dev/null
$ echo $?
[ 0 ]
$ ls /nonexistent > /dev/null 2>&1
$ echo $?
[ 2 ]
# ============================================
# PART 10: DEFAULT VALUES
# ============================================
$ unset NAME
$ echo "${NAME:-Unknown}"
[ Unknown ]
$ NAME="Kronos"
$ echo "${NAME:-Unknown}"
[ Kronos ]
# ============================================
# PART 11: STRING MANIPULATION
# ============================================
$ name="Kronos"
$ echo "Length: ${#name}"
[ Length: 6 ]
$ echo "First 3: ${name:0:3}"
[ First 3: Kro ]
$ echo "Uppercase: ${name^^}"
[ Uppercase: KRONOS ]
$ echo "Lowercase: ${name,,}"
[ Lowercase: kronos ]
# ============================================
# PART 12: EXPORTING
# ============================================
$ EDITOR="nano"
$ bash -c 'echo $EDITOR'
[ ]
$ export EDITOR
$ bash -c 'echo $EDITOR'
[ nano ]
Quick Reference
Declaring and Using Variables
| Action | Syntax |
|---|---|
| Declare | VAR="value" |
| Access | $VAR or ${VAR} |
| Unset | unset VAR |
| Export | export VAR or export VAR=value |
| Read-only | readonly VAR=value |
| Local (function) | local VAR=value |
| From command | VAR=$(command) |
| From input | read -p "Prompt: " VAR |
Special Variables
| Variable | Meaning |
|---|---|
$0 | Script name |
$1–$9 | Positional parameters |
${10} | Parameter 10+ |
$# | Number of arguments |
$* | All args as one word |
$@ | All args as separate words |
$$ | Process ID |
$? | Exit status of last command |
$! | PID of last background command |
$- | Current shell options |
Parameter Expansion
| Syntax | Meaning |
|---|---|
${VAR} | Value of VAR |
${VAR:-default} | Default if unset/empty |
${VAR:=default} | Set and use default if unset |
${VAR:?message} | Error if unset |
${#VAR} | Length |
${VAR:offset:length} | Substring |
${VAR^^} | Uppercase |
${VAR,,} | Lowercase |
${VAR#pattern} | Remove shortest prefix |
${VAR##pattern} | Remove longest prefix |
${VAR%suffix} | Remove shortest suffix |
${VAR%%suffix} | Remove longest suffix |
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Misuse |
| 126 | Not executable |
| 127 | Command not found |
| 130 | Ctrl+C |
Quoting Rules
| Form | Behavior |
|---|---|
$VAR | Word splitting, globbing |
"$VAR" | Literal, no splitting |
'$VAR' | Literal string, no expansion |
"$@" | Preserves argument boundaries |
"$*" | Joins args with first IFS char |
Best Practices
✅ Do This:
# No spaces around =
VAR="value" # ✅
# Quote variables
echo "$VAR" # ✅
# Use braces for clarity
echo "${VAR}_suffix" # ✅
# Use "$@" in loops
for arg in "$@"; do ...; done # ✅
# Provide defaults
echo "${VAR:-default}" # ✅
# Use local in functions
myfunc() { local tmp="x"; ...; } # ✅
# Use uppercase for environment variables
export EDITOR="nano" # ✅
# Use readonly for constants
readonly MAX=100 # ✅
# Check exit codes
if command; then ...; fi # ✅
❌ Don’t Do This:
# Don't put spaces around =
VAR = "value" # ❌ command not found
# Don't leave variables unquoted
echo $VAR # ⚠️ word splitting
# Don't use $* in loops
for arg in $*; do ...; done # ❌ breaks on spaces
# Don't forget braces when adjacent to text
echo "$VAR_file" # ❌ looks for $VAR_file
# Don't reuse special variable names
1="hello" # ❌ invalid
# Don't assume variables persist
# Script variables are local to the script # ⚠️
# Don't use unset variables without defaults
echo "$UNSET" # ⚠️ empty
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
Spaces around = | VAR: command not found | VAR=value |
| Unquoted variable | Word splitting | "$VAR" |
| Missing braces | Wrong expansion | ${VAR}_text |
$* instead of $@ | Breaks on spaces | Use "$@" |
| Variable not exported | Child doesn’t see it | export VAR |
| Local leaks | Function var visible | local VAR |
| Empty unset var | Silent bugs | ${VAR:-default} |
| CRLF line endings | bad interpreter | dos2unix |
Real-World Examples
1. Simple Variable
#!/bin/bash
greeting="Hello, World!"
echo "$greeting"
[ Hello, World! ]
2. Use an Argument
#!/bin/bash
name="$1"
echo "Hello, $name!"
[ Hello, Alice! ]
3. Default Value
#!/bin/bash
name="${1:-Guest}"
echo "Hello, $name!"
[ Hello, Guest! ]
4. Command Substitution
#!/bin/bash
today=$(date +%F)
echo "Today is $today"
[ Today is 2024-01-15 ]
5. User Input
#!/bin/bash
read -p "Your name: " name
echo "Hello, $name"
[ Hello, Alice ]
6. Arithmetic
#!/bin/bash
a=5
b=3
echo "$a + $b = $((a + b))"
echo "$a * $b = $((a * b))"
[ 5 + 3 = 8 ]
[ 5 * 3 = 15 ]
7. Check Argument Count
#!/bin/bash
if [ $# -lt 2 ]; then
echo "Usage: $0 <src> <dst>"
exit 1
fi
echo "Copying $1 to $2"
8. Loop Over Arguments
#!/bin/bash
for arg in "$@"; do
echo "Processing: $arg"
done
[ Processing: one ]
[ Processing: two ]
[ Processing: three ]
9. Safe Temp File with $$
#!/bin/bash
TMP="/tmp/script-$$.tmp"
echo "data" > "$TMP"
# ... use it ...
rm -f "$TMP"
10. Check Exit Status
#!/bin/bash
if ! ls /etc/passwd > /dev/null 2>&1; then
echo "File not found"
exit 1
fi
echo "File exists"
[ File exists ]
11. String Length and Substring
#!/bin/bash
name="Kronos"
echo "Length: ${#name}"
echo "First 3: ${name:0:3}"
[ Length: 6 ]
[ First 3: Kro ]
12. Uppercase and Lowercase
#!/bin/bash
name="Kronos"
echo "${name^^}"
echo "${name,,}"
[ KRONOS ]
[ kronos ]
13. Strip Extension
#!/bin/bash
file="report.pdf"
base="${file%.pdf}"
echo "$base"
[ report ]
14. Strip Path
#!/bin/bash
path="/home/kronos/docs/report.txt"
file="${path##*/}"
echo "$file"
[ report.txt ]
15. Replace in String
#!/bin/bash
path="/home/kronos/docs/report.txt"
new="${path//\//-}"
echo "$new"
[ -home-kronos-docs-report.txt ]
16. Read Multiple Values
#!/bin/bash
read -p "Enter name and age: " name age
echo "Name: $name, Age: $age"
[ Name: Alice, Age: 30 ]
17. Export for Child Processes
#!/bin/bash
export MY_VAR="shared"
bash -c 'echo "Child sees: $MY_VAR"'
[ Child sees: shared ]
18. Read-Only Variable
#!/bin/bash
readonly MAX=100
echo "Max: $MAX"
# MAX=200 # error: read-only variable
[ Max: 100 ]
19. Use Arrays
#!/bin/bash
fruits=("apple" "banana" "cherry")
echo "${fruits[0]}"
echo "${fruits[@]}"
echo "${#fruits[@]}"
[ apple ]
[ apple banana cherry ]
[ 3 ]
20. Associative Arrays (Bash 4+)
#!/bin/bash
declare -A user
user[name]="Kronos"
user[uid]=1000
echo "${user[name]}"
echo "${user[uid]}"
[ Kronos ]
[ 1000 ]
Visual: Variable Lifecycle
┌──────────────────────────────────────────────┐
│ Variable lifecycle │
│ │
│ 1. Declare: │
│ name="Kronos" │
│ │ │
│ ▼ │
│ 2. Use: │
│ echo "Hello, $name" │
│ → [ Hello, Kronos ] │
│ │ │
│ ▼ │
│ 3. Modify: │
│ name="Alice" │
│ echo "$name" │
│ → [ Alice ] │
│ │ │
│ ▼ │
│ 4. Unset: │
│ unset name │
│ echo "$name" │
│ → [ ] │
│ │
└──────────────────────────────────────────────┘
Visual: $* vs $@
┌──────────────────────────────────────────────┐
│ Script called: ./test.sh one two three │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ "$*" │ │
│ │ → [ one two three ] │ │
│ │ (one string) │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ "$@" │ │
│ │ → [ one ] [ two ] [ three ] │ │
│ │ (three separate strings) │ │
│ └────────────────────────────────────────┘ │
│ │
│ Use "$@" to preserve argument boundaries │
│ │
└──────────────────────────────────────────────┘
Summary
| Concept | Syntax | Example |
|---|---|---|
| Declare | VAR="value" | name="Kronos" |
| Access | $VAR | echo "$name" |
| Braces | ${VAR} | echo "${name}_file" |
| Unset | unset VAR | unset name |
| Export | export VAR | export EDITOR |
| From command | VAR=$(cmd) | TODAY=$(date +%F) |
| From input | read VAR | read -p "Name: " name |
| Arithmetic | $((...)) | $((a + b)) |
| Default | ${VAR:-def} | ${NAME:-Guest} |
| Length | ${#VAR} | ${#name} |
| Substring | ${VAR:o:l} | ${name:0:3} |
| Uppercase | ${VAR^^} | ${name^^} |
| Lowercase | ${VAR,,} | ${name,,} |
| Script name | $0 | echo "$0" |
| Arg 1 | $1 | echo "$1" |
| Arg count | $# | echo "$#" |
| All args | "$@" | for a in "$@"; do |
| Process ID | $$ | /tmp/x-$$.tmp |
| Exit status | $? | echo "$?" |
| Background PID | $! | kill $! |
Key takeaways:
- Declare with
VAR="value"— no spaces around= - Access with
$VARor${VAR}— braces avoid ambiguity - Always quote variables —
"$VAR"— unless you want word splitting - Use
$(command)for command substitution - Use
unset VARto remove a variable - Use
export VARto make it visible to child processes - Special variables are provided by the shell —
$0,$1–$9,$#,$*,$@,$$,$? - Use
"$@"in loops and functions — it preserves argument boundaries - Use
$?to check the exit status of the last command - Use
$$for unique temp filenames - Use
${VAR:-default}to provide fallbacks - Use
${#VAR},${VAR:o:l},${VAR^^},${VAR,,}for string manipulation - Use
localinside functions to avoid leaks - Use
readonlyfor constants
Remember: Variables are how scripts remember things. Declare them without spaces, use them with $, quote them always. Special variables like $1, $#, $@, $?, and $$ give your script awareness of its arguments, its environment, and its own execution. Learn parameter expansion — ${VAR:-default}, ${#VAR}, ${VAR^^} — and you can do most string manipulation without calling external tools. Master variables, and you’ve mastered the core of shell scripting.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!