# Bash Tips
## Resources
### [The art of the command line](https://github.com/jlevy/the-art-of-command-line)
### [Google's bash style guide](https://google.github.io/styleguide/shellguide.html#s1.1-which-shell-to-use)
## Notes
### Show the name of the command running on each port on [[macOS]]
[Credit](https://x.com/seldo/status/1823126087423099192) to Laurie Voss (@seldo) on X
*This absurd "one-liner" will show you the name of the command running on each port on MacOS, which is something I need to do constantly so leaving it here:*
```bash
sudo lsof -iTCP -sTCP:LISTEN -n -P \
| awk 'NR>1 {print $9, $1, $2}' \
| sed 's/.*://' \
| while read port process pid; do echo "Port $port: $(ps -p $pid -o command= \
| sed 's/^-//') (PID: $pid)"; done \
| sort -n
```
### Remove ANSI color codes from stdout log output
```bash
sed -r "s/\x1B\[(([0-9]{1,2})?(;)?([0-9]{1,2})?)?[m,K,H,f,J]//g" file_name
```
[Source](https://stackoverflow.com/a/30938702)
Example usage with [[Cargo]] test:
```bash
cargo test -p smoketest user_recvs_jit_from_user | tee | sed -r 's/\x1B\[(([0-9]{1,2})?(;)?([0-9]{1,2})?)?[m,K,H,f,J]//g' | tee log/log.txt
```
### [Using arguments from the previous command](https://stackoverflow.com/q/4009412)
`!!` gives you the entire last command.
`!
gives you the last argument of the last command.
`!:n` gives you the nth token of the last command, 0 indexed.
```bash
$ cat file.txt
$ echo !:0 # Expands to `echo cat`
$ cat file.txt
$ echo !:1 # Expands to `echo file.txt`
$ TEMP=1 cat file.txt
$ echo !:0 # Expands to `echo TEMP=1`
```
### (Guide) [Bash parameter expansion](https://linuxhint.com/bash_parameter_expansion/)
So you can know wtf is going on in the PATH assignment here:
```bash
if [[ ! "$PATH" == *$(brew --prefix)/opt/fzf/bin* ]]; then
PATH="${PATH:+${PATH}:}/opt/homebrew/opt/fzf/bin"
fi
```
### If / elif / else syntax
```bash
if [[ "bash" == $0 ]]; then
echo "Running bash"
elif [[ "zsh" == $0 ]]; then
echo "Running zsh"
else
echo "Running something else: $0"
fi
```
### Running scripts that set environment variables
- `. env.sh` or `source env.sh` actually updates the env variables
- Check with `env`
- `./env.sh` does not
### [Defining a Bash Variable With or Without ‘export’](https://www.baeldung.com/linux/bash-variables-export)
- *Shell variables (defined without export) are like local variables that we can access only within that shell.*
- *Environment variables (defined with export) are like global variables that we can access within the defining shell and all its child shells, processes, and commands.*
### Run a binary in the background
https://www.linuxquestions.org/questions/linux-newbie-8/how-to-run-any-binary-in-background-background-process-218120/
```bash
./daemon &
```
OR
```bash
./daemon
^Z daemon suspended
bg # run in background
```
### Examining binaries
```bash
$ xxd Body.data | head -n15
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: f74d 7001 0000 0000 ffff ffff 2000 0000 .Mp......... ...
00000050: 0000 0000 da02 0000 ffff ffff ffff ffff ................
00000060: 9480 0000 9080 0000 443b 0400 78da ecbd ........D;..x...
00000070: 6b8c 2457 961e 26ed 6ab5 6fc9 300c c382 k.$W..&.j.o.0...
00000080: 21e3 aac7 10ab b455 3df9 7eb0 67da aa6e !......U=.~.g..n
00000090: 72d8 3d7c 0cc5 2667 b05a 8c1b 3723 6e66 r.=|..&g.Z..7#nf
000000a0: 5c56 44dc e4bd 1155 9dc4 1a18 6261 9918 \VD....U....ba..
000000b0: 717f 505c db4b 2cb4 c66a e911 966b 4382 q.P\.K,..j...kC.
000000c0: b570 0bd6 2f75 f71a ae69 0c2c ff31 6003 .p../u...i.,.1`.
000000d0: b6e1 010c 0102 2c03 fee3 1f86 1fe7 dc1b ......,.........
000000e0: 9195 8f88 cc8c c81b 9955 2407 c3ae aacc .........U$.....
```
Source: https://fmentzer.github.io/posts/2020/dictionary/
### [Examine dynamic linking requirements of binary executable](https://users.rust-lang.org/t/compile-on-ubuntu-and-run-on-rhel/11727/4)
e.g. after running `cargo run --release`
```bash
$ readelf -V target/release/hellorustsgx
Version symbols section '.gnu.version' contains 75 entries:
Addr: 0x0000000000000f40 Offset: 0x000f40 Link: 5 (.dynsym)
000: 0 (*local*) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5)
004: 2 (GLIBC_2.2.5) 3 (GCC_3.3) 4 (GLIBC_2.2.5) 4 (GLIBC_2.2.5)
008: 0 (*local*) 2 (GLIBC_2.2.5) 4 (GLIBC_2.2.5) 5 (GLIBC_2.18)
00c: 6 (GLIBC_2.3.4) 2 (GLIBC_2.2.5) 7 (GCC_3.0) 4 (GLIBC_2.2.5)
010: 7 (GCC_3.0) 7 (GCC_3.0) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5)
014: 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 4 (GLIBC_2.2.5) 4 (GLIBC_2.2.5)
018: 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 8 (GCC_4.2.0)
01c: 4 (GLIBC_2.2.5) 4 (GLIBC_2.2.5) 7 (GCC_3.0) 2 (GLIBC_2.2.5)
020: 2 (GLIBC_2.2.5) 9 (GLIBC_2.3) 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5)
024: 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 0 (*local*)
028: a (GLIBC_2.3) b (GLIBC_2.14) 7 (GCC_3.0) 4 (GLIBC_2.2.5)
02c: 4 (GLIBC_2.2.5) 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5)
030: 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) c (GLIBC_2.28)
034: 4 (GLIBC_2.2.5) 7 (GCC_3.0) 2 (GLIBC_2.2.5) 7 (GCC_3.0)
038: 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5)
03c: 2 (GLIBC_2.2.5) 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5)
040: 4 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 0 (*local*) 7 (GCC_3.0)
044: 2 (GLIBC_2.2.5) 7 (GCC_3.0) 4 (GLIBC_2.2.5) 4 (GLIBC_2.2.5)
048: 4 (GLIBC_2.2.5) 7 (GCC_3.0) 2 (GLIBC_2.2.5)
Version needs section '.gnu.version_r' contains 4 entries:
Addr: 0x0000000000000fd8 Offset: 0x000fd8 Link: 6 (.dynstr)
000000: Version: 1 File: ld-linux-x86-64.so.2 Cnt: 1
0x0010: Name: GLIBC_2.3 Flags: none Version: 9
0x0020: Version: 1 File: libpthread.so.0 Cnt: 1
0x0030: Name: GLIBC_2.2.5 Flags: none Version: 4
0x0040: Version: 1 File: libgcc_s.so.1 Cnt: 3
0x0050: Name: GCC_4.2.0 Flags: none Version: 8
0x0060: Name: GCC_3.0 Flags: none Version: 7
0x0070: Name: GCC_3.3 Flags: none Version: 3
0x0080: Version: 1 File: libc.so.6 Cnt: 6
0x0090: Name: GLIBC_2.28 Flags: none Version: 12
0x00a0: Name: GLIBC_2.14 Flags: none Version: 11
0x00b0: Name: GLIBC_2.3 Flags: none Version: 10
0x00c0: Name: GLIBC_2.3.4 Flags: none Version: 6
0x00d0: Name: GLIBC_2.18 Flags: none Version: 5
0x00e0: Name: GLIBC_2.2.5 Flags: none Version: 2
```
### Examine requirements using `ppd`
### Count lines of code
```bash
brew install tokei
tokei .
```
### [Difference between `>>` and `tee -a`](https://unix.stackexchange.com/a/464654)
**TL;DR:** `tee -a` is superior to `>>`
There's no difference in the sense that the data _in the file_ will be the same if `echo` and `tee` are executed successfully and if the file is writable by the current user.
The `tee` command would additionally produce output on _its_ standard output, showing the text that would also be appended to the file. This would not happen in the first command.
Another difference is that if the file can _not_ be written to, then the first command, with the redirection, would not even run the `echo`, whereas the `echo` _would_ run in the second command, but `tee` would fail in writing to the file (`tee` would still produce text on the terminal though).
This could be significant in the case where you run some long running process that produces output:
```
long_running_thing >>file
```
This would not even start `long_running_thing` if `file` was not writable.
```
long_running_thing | tee -a file
```