Glam Prestige Journal

Bright entertainment trends with youth appeal.

I'm working on a script that lets me delete old public keys from a server via ssh. The issue seems to come from the formatting of my ssh command here:

ssh -qo ConnectTimeout=20 "${user_ssh}@${ip}" "sed -ein \"s|ssh-rsa\s${fingerprint}\s\(.*\)|#---> deleted by public-key-remover.sh. USER:\1|g\" $key_dir || exit 67"

$fingerprint is the fingerprint of the rsa public key.

$key_dir is the location of the public key file.

I made sure $key_dir does exists but it's still printing out following error:

sed: can't read s|ssh-rsa\sAAAAB3NzaC1yc2EAAAADAQABAAABAQCDlMyH7CX5ckyspCDx8pqzLv41OM0xjlrSeHhi8gz+6jXepaWDtcrlGzkieN3oOK+uUJKT5Jz8uSRBoTfr20tTLLHklRASoWiy7EvACwqfClRVnC67KBWKWlsIDLBGC3KDkJQbYD8ovDP6svy7xBMW0J1RWnQW/RqaCZ9udFMzh5KUbCCm360eVNnFq7fAR//ZeUHNlTGFfSl/WfxkjacAAfKGjtnxYHfo8N/IGP9rbGoX/nlU8XOr2y9uHkVHt+ghG8/wnZo1quUua8JbjMOv6Ygu40Qe9E5pXKOZr1v1RkvMrNOoZ9O8KNvVt7L5+0TvM2NG7AK51qo9ZpHNPr2b\s\(.*\)|#---> deleted by public-key-remover.sh. USER:\1|g: No such file or directory

Since I'm very new to bash, I would love some assistance.

3 Answers

Main issue

The main issue here is that -e in sed -ein … is an option that requires an option-argument, a sed script to be executed. in happens to be a valid sed script and is taken as such. What follows is then interpreted as path(s) to file(s) to be processed. As if the command on the remote side was sed -e in ….

I'm not sure it's the only problem, but I'm sure this is why your sed interpreted s|ssh-rsa… as a path.

If you want to pass -n and -e options in a compact form then -e must be the last one because it requires an option-argument (-n doesn't). The option-argument (i.e. your sed script) must immediately follow:

sed -i -ne …

I separated -i because -isomething has meaning (possibly different than -i something) and you apparently don't want it here, you want -i.

A straightforward way is to specify the options one by one:

sed -i -n -e …

but I really doubt you want -n. Your sed script does not explicitly print anything, so with -n it will be silent. This means with -i -n your sed script will wipe out the content of the file(s).

Note if you tried sed -e -i …, then sed would complain about - being an unknown command, which would be a very different error than what you got. It's because -i is not a valid sed script, while your in accidentally is.


Broader picture

There are few conventions we can observe here:

  1. -n option of sed neither requires not accepts an option-argument, another option can follow n inside a single argument starting with -. sed -nwhatever is equivalent to sed -n -whatever and the meaning of -whatever depends on what -w means to sed. The convention that -abc means -a -b -c is quite common for options that don't require option-arguments.

  2. -e option of sed requires an option-argument. sed -ewhatever is equivalent to sed -e whatever. This convention is quite common for options that require option-arguments.

  3. -i option of GNU sed may or may not take an option-argument. When you want to specify one, you need to concatenate it with -i. -iwhatever is not equivalent to -i whatever nor to -i -whatever. This convention is not so common. Note the option is not portable. The sed you're using may or may not be GNU sed. Compare this thread: sed -i empty argument compatibility issue.

    Unfortunately that is a GNU sed extension and use of it is intrinsically not portable usage. And the FreeBSD use of -i is a similar but slightly incompatible usage. The -i option is not specified by POSIX and so any use of it is non-standard by definition.

    -n and -e are specified by POSIX.

There may be other conventions. Unfortunately manuals are rarely helpful in learning what tool follows what conventions of this type. Often good tools that do follow common conventions don't bother stating (in their manuals) that they do, maybe because "everyone should follow, it's obvious". And not-so-good tools often don't bother stating that they don't follow because they don't care; if they cared, they would follow in the first place. This is my impression, my guess. Then there are tools that don't even follow the convention of starting options with a dash (for various reasons).

My point is you can learn respective options from man sed, man ls or man du, but the fact you can do ls -hls or du -hms is not explicitly documented there. Acknowledge the common conventions, try them with tools that are new for you. Many will follow, some may not (or not fully). When in doubt, specify options as separate arguments.


Side note

Some values of $key_dir will be problematic. Keep in mind the remote shell will interpret the whole string again (what if $key_dir expands to a string with spaces? or with "? '? $(reboot)?). If your local shell is Bash then use ${key_dir@Q}. Bash will expand the variable in a special way, so after the result is parsed in a (remote) shell, it becomes the original string again. The expanded string is properly quoted and/or escaped.

The -i option to sed takes an extension for the backup file, so don't bundle that option with others.

Also, -n stops sed from printing lines, so you'll end up with an empty file.

Embedded backslashes should be escaped.

The -E option means parentheses don't need to be escaped.

Try this (with extra newlines for added readability)

ssh -qo ConnectTimeout=20 "${user_ssh}@${ip}" " sed -i -E 's|ssh-rsa\\s${fingerprint}\\s(.*)|#---> deleted by public-key-remover.sh. USER:\\1|g' '$key_dir' || exit 67
"

From Ask Ubuntu, answer by Javi M.

idssh=$(awk '{print $2}' ~/.ssh/id_rsa.pub)
ssh $remote "sed -i '\#$idssh#d' .ssh/authorized_keys"
4

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy