Skip to content

Commit bb2b589

Browse files
committed
new version
1 parent d8062b1 commit bb2b589

File tree

4 files changed

+295
-69
lines changed

4 files changed

+295
-69
lines changed

README.md

Lines changed: 151 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,170 @@
11
# sshko
2-
Your are lazy and can not remember ssh connection? Then this is for you! This is a ssh connection manager. It can be easy modified.
32

4-
![](img/pic2.png)
3+
🚀 **sshko** is a simple SSH connection manager for lazy people (and proud of it!).
4+
Stop memorizing hostnames, ports, and SSH flags — just save them once and pick from a dialog menu next time.
55

6-
## Usage
7-
* copy sshko.sh and put it where you want (I put it in user home dir ~/)
8-
* make an alias
9-
```
10-
alias sshko="~/sshko.sh $@"
6+
![](img/screenshot.png)
7+
8+
---
9+
10+
## ✨ Features
11+
12+
- Automatically logs every SSH connection you make via `sshko`.
13+
- Stores connections (with optional notes) in `~/.sshLog.txt` (CSV format).
14+
- Supports advanced SSH options, e.g. `-p 3002 user@host`.
15+
- Interactive **dialog menu** with:
16+
- **Connect** — jump straight into SSH.
17+
- **Delete** — remove entries you don’t need anymore.
18+
- **Cancel** — quit the menu.
19+
- Super easy to tweak: it’s just a bash script.
20+
21+
---
22+
23+
## 📦 Requirements
24+
25+
- `ssh`
26+
- `dialog` (for the menu UI)
27+
28+
Install `dialog` if missing:
29+
30+
**Debian/Ubuntu**
31+
32+
```bash
33+
sudo apt install ssh dialog
1134
```
12-
* try it:
35+
36+
**Fedora/RHEL**
37+
38+
```bash
39+
sudo dnf install openssh dialog
1340
```
41+
42+
---
43+
44+
## ⚡ Installation
45+
46+
1. Copy `sshko.sh` to your home directory (or anywhere you like):
47+
```bash
48+
cp sshko.sh ~/
49+
```
50+
2. Make it executable:
51+
```bash
52+
chmod +x ~/sshko.sh
53+
```
54+
3. Add an alias to your shell config (`~/.bashrc` or `~/.zshrc`):
55+
```bash
56+
alias sshko="~/sshko.sh $@"
57+
```
58+
4. Reload your shell:
59+
```bash
60+
source ~/.bashrc
61+
```
62+
63+
---
64+
65+
## 🛠 Usage
66+
67+
### First run
68+
69+
```bash
1470
sshko
1571
```
16-
it should output a message
17-
```
18-
ssh log file is empty
72+
73+
If no connections are saved yet, you’ll see:
74+
1975
```
20-
try to use it with ssh connection (same like ssh command)
76+
ssh log file is empty
2177
```
78+
79+
### Add a new connection
80+
81+
Use `sshko` the same way you’d use `ssh`:
82+
83+
```bash
2284
2385
```
24-
it will save the connection and execute ssh and then ask you for password
2586

26-
if you try it again without argument it will show you a dialog will all ssh connections
87+
- The connection is saved to `~/.sshLog.txt`.
88+
- You’ll be prompted for an optional note (e.g., _Home server_).
89+
- `sshko` then connects you right away.
90+
91+
Example entry in `~/.sshLog.txt`:
92+
93+
```
94+
[email protected], Home server
95+
```
96+
97+
### Advanced SSH with options
98+
99+
You can store full SSH specs, including flags:
100+
101+
```bash
102+
sshko -p 3002 [email protected]
103+
```
104+
105+
Saved as:
106+
27107
```
108+
-p 3002 [email protected], Jenkins
109+
```
110+
111+
### Open the menu
112+
113+
Run:
114+
115+
```bash
28116
sshko
29117
```
30-
![](img/pic1.png)
31-
Basically it saves every connection in ~/.sshLog.txt file
32118

119+
You’ll get a dialog menu like this:
120+
121+
```
122+
SSH | NOTE
123+
--------------------------------- | ----------------
124+
[email protected] | Home server
125+
-p 3002 [email protected] | Jenkins
126+
```
127+
128+
From here you can:
129+
130+
- **Connect** to a host
131+
- **Delete** an entry
132+
- **Cancel** to exit
133+
134+
![](img/screenshot.png)
135+
136+
---
137+
138+
## 📂 Data storage
139+
140+
Connections are stored in:
141+
142+
```
143+
~/.sshLog.txt
144+
```
145+
146+
Each line is:
147+
148+
```
149+
<ssh command>, <note>
150+
```
151+
152+
Examples:
153+
154+
```
155+
[email protected], Home server
156+
-p 3002 [email protected], Jenkins
157+
```
158+
159+
You can edit this file manually if you want to rename notes or reorder connections.
160+
161+
---
162+
163+
## 🎉 Why sshko?
33164

34-
Now you don't need to remember any ssh connections, just call `sshko` and it will show you all ssh used connections.
35-
![](img/pic2.png)
165+
Because you’re lazy 😅 — and that’s a feature.
166+
Why memorize every host, port, and flag when you can just run `sshko` and pick from a menu?
36167

37-
## Requirements
38-
* installed `ssh`
168+
---
39169

40-
Happy sshing !!! :)
170+
Happy SSH-ing! 🔑✨

img/pic1.png

-18.4 KB
Binary file not shown.

img/pic2.png

-35.6 KB
Binary file not shown.

sshko.sh

Lines changed: 144 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,153 @@
11
#!/bin/bash
22

33
logFile=~/.sshLog.txt
4-
#logFile=./file.txt
4+
[[ -e "$logFile" ]] || : > "$logFile"
55

6-
if [[ ! -e ${logFile} ]]; then
7-
touch ${logFile}
8-
fi
6+
# -------- Formatting helpers --------
7+
fmt_row() {
8+
local left="$1" note="$2" left_w="$3" note_w="$4"
9+
note="${note//$'\n'/ }"
10+
[[ ${#left} -gt $left_w ]] && left="${left:0:$((left_w-1))}"
11+
[[ ${#note} -gt $note_w ]] && note="${note:0:$((note_w-1))}"
12+
printf "%-${left_w}s | %-${note_w}s" "$left" "$note"
13+
}
914

10-
if [ "$1" == "" ] || [ $# -gt 1 ]; then
11-
if ! [ -s ${logFile} ]; then
12-
echo "ssh log file is empty"
13-
exit
14-
fi
15-
16-
HEIGHT=20
17-
WIDTH=40
18-
CHOICE_HEIGHT=9
19-
BACKTITLE="This is made, because you are super lazy!!!!"
20-
TITLE="SSHko"
21-
MENU="Choose one of the following ssh connections:"
22-
23-
arr=()
24-
val=()
25-
key=0
26-
while IFS= read -r line || [[ "$line" ]]; do
27-
arr+=($key "$line")
28-
val+=("$line")
29-
((key = key + 1))
30-
done <${logFile}
31-
32-
for key in "${!arr[@]}"; do
33-
echo ${arr[$key]}
34-
done
15+
# -------- File helpers --------
16+
# Build arrays from file:
17+
# menu_pairs[]: <idx> "<formatted row>"
18+
# specs[]: left field (ssh spec)
19+
# notes[]: note
20+
# lines[]: trimmed full line as stored
21+
build_arrays() {
22+
menu_pairs=(); specs=(); notes=(); lines=()
23+
local key=0
24+
while IFS= read -r raw || [[ -n "$raw" ]]; do
25+
[[ -z "$raw" || "$raw" =~ ^[[:space:]]*# ]] && continue
26+
# Normalize line (trim)
27+
local line="$raw"
28+
line="${line#"${line%%[![:space:]]*}"}"
29+
line="${line%"${line##*[![:space:]]}"}"
3530

36-
echo ${#arr[@]}
37-
38-
CHOICE=$(dialog --clear --title "$TITLE" --backtitle "$BACKTITLE"\
39-
--menu "$MENU" $HEIGHT $WIDTH $CHOICE_HEIGHT "${arr[@]}" \
40-
2>&1 >/dev/tty)
41-
clear
42-
if [[ ! $CHOICE == "" ]]; then
43-
sshHost=${val[$CHOICE]}
44-
echo "$CHOICE You chose ${sshHost}"
45-
ssh ${sshHost}
46-
exit
47-
fi
48-
else
49-
sshHost=$1
50-
# echo ${sshHost} >> ${logFile}
51-
if ! grep -Fxq "$sshHost" ${logFile}; then
52-
echo ${sshHost} >>${logFile}
53-
fi
31+
local left="${line%%,*}"
32+
local note="${line#*,}"
33+
[[ "$note" == "$line" ]] && note=""
34+
35+
# Trim fields
36+
left="${left#"${left%%[![:space:]]*}"}"; left="${left%"${left##*[![:space:]]}"}"
37+
note="${note#"${note%%[![:space:]]*}"}"; note="${note%"${note##*[![:space:]]}"}"
38+
39+
local label; label=$(fmt_row "$left" "$note" "$LEFT_W" "$NOTE_W")
40+
menu_pairs+=("$key" "$label")
41+
specs+=("$left")
42+
notes+=("$note")
43+
lines+=("$line")
44+
((key++))
45+
done < "$logFile"
46+
}
47+
48+
# Delete entry by index safely (rewrite file)
49+
delete_index() {
50+
local del="$1"
51+
local tmp
52+
tmp=$(mktemp)
53+
local i=0
54+
while IFS= read -r raw || [[ -n "$raw" ]]; do
55+
# keep comments/blank lines as-is in output
56+
if [[ -z "$raw" || "$raw" =~ ^[[:space:]]*# ]]; then
57+
echo "$raw" >> "$tmp"
58+
continue
59+
fi
60+
# Align with lines[] by trimming same way
61+
local line="$raw"
62+
line="${line#"${line%%[![:space:]]*}"}"
63+
line="${line%"${line##*[![:space:]]}"}"
64+
65+
# Only count non-comment, non-empty lines toward index
66+
if [[ $i -ne $del ]]; then
67+
echo "$line" >> "$tmp"
68+
fi
69+
((i++))
70+
done < "$logFile"
71+
mv "$tmp" "$logFile"
72+
}
73+
74+
# -------- Menu / actions --------
75+
show_menu() {
76+
while true; do
77+
if ! [ -s "$logFile" ]; then
78+
echo "ssh log file is empty"
79+
exit 1
80+
fi
81+
82+
HEIGHT=22
83+
WIDTH=90
84+
CHOICE_HEIGHT=18
85+
BACKTITLE="This is made, because you are super lazy!!!!"
86+
TITLE="SSHko"
87+
MENU="Choose one of the following ssh connections:"
5488

55-
ssh ${sshHost}
89+
LEFT_W=48
90+
NOTE_W=$(( WIDTH - 10 - LEFT_W ))
91+
92+
build_arrays
93+
if [[ ${#menu_pairs[@]} -eq 0 ]]; then
94+
echo "ssh log file is empty"
95+
exit 1
96+
fi
97+
98+
header=$(fmt_row "SSH" "NOTE" "$LEFT_W" "$NOTE_W")
99+
CHOICE=$(dialog --clear --title "$TITLE" --backtitle "$BACKTITLE" \
100+
--ok-label "Connect" --cancel-label "Exit" \
101+
--extra-button --extra-label "Delete" \
102+
--menu "$MENU\n$header" \
103+
$HEIGHT $WIDTH $CHOICE_HEIGHT "${menu_pairs[@]}" \
104+
2>&1 >/dev/tty)
105+
status=$?
106+
clear
107+
108+
case $status in
109+
0) # Connect
110+
[[ -z "$CHOICE" ]] && continue
111+
spec="${specs[$CHOICE]}"
112+
IFS=' ' read -r -a SSHARGS <<< "$spec"
113+
exec ssh "${SSHARGS[@]}"
114+
;;
115+
3) # Delete (extra button)
116+
[[ -z "$CHOICE" ]] && continue
117+
full_line="${lines[$CHOICE]}"
118+
dialog --yesno "Delete this entry?\n\n${full_line}" 8 70
119+
confirm=$?
120+
clear
121+
if [[ $confirm -eq 0 ]]; then
122+
delete_index "$CHOICE"
123+
# Loop to refresh menu after deletion
124+
fi
125+
;;
126+
1|255) # Cancel / ESC
127+
exit 0
128+
;;
129+
esac
130+
done
131+
}
132+
133+
# -------- Main behavior --------
134+
if [[ $# -eq 0 ]] || [[ $# -gt 1 && "$1" == "--menu" ]]; then
135+
show_menu
56136
exit
57137
fi
138+
139+
# Called with args: treat ALL args as ssh spec; add if missing, then connect
140+
sshSpec="$*"
141+
# Exists already?
142+
if awk -v s="$sshSpec" -F',' '
143+
{ gsub(/^[ \t]+|[ \t]+$/,"",$1); if ($1==s){found=1; exit} }
144+
END { exit found?0:1 }
145+
' "$logFile"; then
146+
IFS=' ' read -r -a SSHARGS <<< "$sshSpec"
147+
exec ssh "${SSHARGS[@]}"
148+
else
149+
read -r -p "Enter a note for [${sshSpec}] (optional): " note
150+
echo "${sshSpec}, ${note}" >> "$logFile"
151+
IFS=' ' read -r -a SSHARGS <<< "$sshSpec"
152+
exec ssh "${SSHARGS[@]}"
153+
fi

0 commit comments

Comments
 (0)