diff --git a/README.md b/README.md index b7ff3b2..8adafb3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # sshcd +### This is a fork of fraction/sshcd with support for remote command execution + Tired of having to type this janky command to [ssh](http://manpages.ubuntu.com/manpages/saucy/en/man1/ssh.1.html) and [cd](http://manpages.ubuntu.com/manpages/saucy/en/man1/cd.1posix.html) into unfamiliar remote servers? ```sh @@ -12,19 +14,26 @@ Stop it. Connect with SSH and cd (change directory) with one command. sshcd user@fraction.io:/foo/bar ``` +## Requirements + +- Bash shell (the script requires bash, not sh or zsh) +- curl (for installation via provided commands) + ## Installation -Use Homebrew to download and install the executable. +Add the executable into your PATH and give it execute permissions. + +Mac example: ```sh -brew tap fraction/homebrew-formulae -brew install sshcd +sudo curl -Lo ~/.local/bin/sshcd https://raw.githubusercontent.com/romanesko/sshcd/refs/heads/master/sshcd +sudo chmod +x ~/.local/bin/sshcd ``` -Add the executable into your path and give it permissions. +Linux example: ```sh -sudo curl -Lo /usr/local/bin/sshcd http://git.io/wfAXEQ +sudo curl -Lo /usr/local/bin/sshcd https://raw.githubusercontent.com/romanesko/sshcd/refs/heads/master/sshcd sudo chmod +x /usr/local/bin/sshcd ``` @@ -36,15 +45,36 @@ The default usage is pretty simple. sshcd user@fraction.io:/foo/bar ``` -The tool supports prepended flags, too! +Execute a remote command: + +```sh +sshcd user@fraction.io:/foo/bar ls -la +``` + +Execute a complex command (multiple commands): + +```sh +sshcd user@fraction.io:/foo/bar bash -c 'sudo df -h ~' +``` + +The tool supports prepended ssh flags as well: ```sh sshcd -v user@fraction.io:/foo/bar ``` + +### Spaces and special characters + +Paths and remote commands with spaces or special characters are supported and properly escaped. + +### Error handling + +If you do not provide a target in the form [user@]host:/path, the script will print usage instructions and exit with an error. + ## Support -Please [open an issue](https://github.com/fraction/sshcd/issues/new) for questions and concerns. +Please [open an issue](https://github.com/romanesko/sshcd/issues/new) for questions and concerns. ## Contributing -Fork the project, commit your changes, and [open a pull request](https://github.com/fraction/sshcd/compare/). +Fork the project, commit your changes, and [open a pull request](https://github.com/romanesko/sshcd/compare/). diff --git a/sshcd b/sshcd index 031370c..cf57dd6 100755 --- a/sshcd +++ b/sshcd @@ -1,34 +1,44 @@ #!/bin/bash -e -options=("${@:1:$(($# - 1))}") # Everything in "$@" except the last argument -target="${!#}" # The last argument from "$@" -# Get user -usertest="${target%%:*}" -if [ ! "${usertest/@/}" = "${usertest}" ]; then # user is included in the target - user="${target%%@*}" # Get user - target="${target#*@}" # Strip out user -fi +options=() +target="" +remote_cmd=() +user="" +path="" -# Get hostname and path -if [ "${target::1}" = "[" ]; then # Syntax: [user@]\[hostname\]:path - remote="${target%\]*}]" - path="${target#*\]}" - if [ -z "${path}" ]; then - exec ssh "$@" - fi - path="${path:1}" -else # Syntax: [user@]hostname:path - remote="${target%%:*}" - path="${target#*:}" - if [ "${path}" = "${target}" ]; then - exec ssh "$@" +for arg in "$@"; do + if [[ -z "$target" && "$arg" == *:* ]]; then + target="$arg" + elif [[ -z "$target" ]]; then + options+=("$arg") + else + remote_cmd+=("$arg") fi +done + +if [[ -z "$target" ]]; then + echo "Usage: $0 [ssh options] [user@]host:/path [command]" >&2 + exit 1 +fi + +usertest="${target%%:*}" +path="${target#*:}" + +if [[ "$usertest" == *"@"* ]]; then + user="${usertest%%@*}" + host="${usertest#*@}" +else + host="$usertest" fi -# Construct target argument for ssh -if [ ! "${usertest/@/}" = "${usertest}" ]; then # user is included in the target - remote="${user}@${remote}" # Reattach user +[[ -n "$user" ]] && remote="${user}@${host}" || remote="${host}" + +path_escaped=$(printf "%q" "$path") + +if [[ ${#remote_cmd[@]} -gt 0 ]]; then + cmd=$(printf "%q " "${remote_cmd[@]}") + exec ssh "${options[@]}" "${remote}" "cd $path_escaped && exec $cmd" +else + exec ssh -t "${options[@]}" "${remote}" "cd $path_escaped; exec \$SHELL -l" fi -path="${path/\'/\'\\\'\'}" -exec ssh -t "${options[@]}" "${remote}" "cd '${path}'; exec \$SHELL -l"