history expansion by complete first word - zsh

Consider that I've successfully run these two commands in this order (but perhaps many commands ago):
~% ssh localhost echo
~% sshfs localhost:/ /media/copy-of-root
Now I would like to rerun the ssh command. My first instinct is to use !ssh, but this will match the sshfs command instead.
Is there a version of history expansion which will match entire first words instead of prefixes of commands? If not, is there some other robust way to choose the ssh command over the sshfs one?

well, if you search for ssh (with a trailing space) it will find it. IMO the best alternative is to bind up and down to up-line-or-search and down-line-or-search.
bindkey '^[[A' up-line-or-search # check the exact code for your UP key...
Then you would just use:
% ssh [UP]
which would search for ssh in your history. If that is not the history instance you want, just keep searching (i.e. hitting "UP").

Related

SCP issue with multiple files - UNIX

Getting error in copying multiple files. Below command is copying only first file and giving error for rest of the files. Can someone please help me out.
Command:
scp $host:$(ssh -n $host "find /incoming -mmin -120 -name 2018*") /incoming/
Result:
user#host:~/scripts/OTA$ scp $host:$(ssh -n $host "find /incoming -mmin -120 -name 2018*") /incoming/
Password:
Password:
2018084session_event 100% |**********************************************************************************************************| 9765 KB 00:00
cp: cannot access /incoming/2018084session_event_log.195-10.45.40.9
cp: cannot access /incoming/2018084session_event_log.195-10.45.40.9_2_3
Your command uses Command Substitution to generate a list of files. Your assumption is that there is some magic in the "source" notation for scp that would cause multiple members of the list generated by your find command to be assumed to live on $host, when in fact your command might expand into something like:
scp remotehost:/incoming/someoldfile anotheroldfile /incoming
Only the first file is being copied from $host, because none of the rest include $host: at the beginning of the path. They're not found in your local /incoming directory, hence the error.
Oh, and in addition, you haven't escape the asterisk in the find command, so 2018* may expand to multiple files that are in the login directory for the user in question. I can't tell from here, it depends on your OS and shell configuration.
I should point out that you are providing yet another example of the classic Parsing LS problem. Special characters WILL break your command. The "better" solution usually offered for this problem tends to be to use a for loop, but that's not really what you're looking for. Instead, I'd recommend making a tar of the files you're looking for. Something like this might do:
ssh "$host" "find /incoming -mmin -120 -name 2018\* -exec tar -cf - {} \+" |
tar -xvf - -C /incoming
What does this do?
ssh runs a remote find command with your criteria.
find feeds the list of filenames (regardless of special characters) to a tar command as options.
The tar command sends its result to stdout (-f -).
That output is then piped into another tar running on your local machine, which extracts the stream.
If your tar doesn't support -C, you can either remove it and run a cd /incoming before the ssh, or you might be able to replace that pipe segment with a curly-braced command: { cd /incoming && tar -xvf -; }
The curly brace notation assumes a POSIX-like shell (bash, zsh, etc). The rest of this should probably work equally well in csh if that's what you're stuck with.
Limited warranty: Best Effort Only. Untested on animals or computers. Your milage may vary. May contain nuts.
If this doesn't work for you, poke at it until it does.

how to add commands in .ssh/authorized_keys

I read on man sshd one can add post-login processing when a user logs in using a particular key:
environment="FOO=BAR" ssh-rsa AAA... keytag
But when I try to ssh into the system, the target host does not register the line and instead asks for a password. What is the right way of adding this? I would like to do something like
command="echo|mail -s ${USER},${HOSTNAME} a.monitored.email#example.com" ssh-rsa AAA... keytag
I am using Suse SLE 11 SP2.
Thanks
Dinesh
First, according to the documentation command = "command":
That specifies the command is executed Whenever This key is used for authentication. The command supplied by the user (if any) is ignored. The command is run on a pty if the client requests a pty; Otherwise it is run without a tty. If an 8-bit clean channel is required, one must not request a pty or specify no-pty Should. A quote May be included in the command by quoting it with a backslash. This option might be useful to restrict Un certain public keys to perform just a specific operation. An example might be a key That Permits remote backups but nothing else. Note That May specify the client TCP and / or X11 forwarding Explicitly UNLESS they 'are prohibited. The command originally supplied by the client is available in the SSH_ORIGINAL_COMMAND environment variable. Note That This option Applies to shell, command or subsystem execution. Also note This command That May be superseded by Either a sshd_config (5) ForceCommand directive or a command embedded in a certificate.
Using this option, it is possible to enforce execution of a given command when this key is used for authentication and no other.This is not what you're looking for.
To run a command after login you can add in the file ~/bashrc something like this:
if [[ -n $SSH_CONNECTION ]] ; then
echo|mail -s ${USER},${HOSTNAME} a.monitored.email#example.com"
fi
Second, you need to verify the permissions of the authorized_keys file and the folder / parent folders in which it is located.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
For more information see: https://www.complang.tuwien.ac.at/doc/openssh-server/faq.html#3.14

Can I include a password in my rsync call?

I use rsync to update my static website. I currently cd to the local website directory, and run the rsync command, and then enter the password in the next line. I've saved my rsync call into a text snippet (such that _rs just expands to my call). Is there way to use something like a -p flag at the end and include the password too?
My call looks like this:
rsync -avzh -e ssh * foo#foo.org:"/home/foo/public_html/"
Answering this with a direct answer to the question, may be useful in less secure scenarios.
#!/usr/bin/expect -f
set PASSPH "123456"
send_user "\n"
stty -echo
spawn rsync -apv -e ssh "/Volumes/Macintosh HD/Users/charliechaplin/test/" "charly#chaplin.com:/project/htdocs/site/"
expect "password:"
send "$PASSPH\n"
expect "#"
One of option is use public/private key pair, see How to auto rsync with ssh passwordless
Or you can try use Expect

mysql bash_profile password to be ignored

I was looking for unix bash history to give * for mysql password.
Eg: If I issue -
mysql -uroot -psecuritydemon -h192.168.90.888
then in unix prompt if I use history | grep -i mysql -> I get the password entry too.. Instead I would like to see for the history grep result as below
mysql -uroot -p*** -h192.168.90.888
Any way to achieve this?
I don't think it is possible to filter the command that is written to your history in bash. However, I would suggest you use a ~/.my.cnf configuration file as described here: http://support.modwest.com/content/6/242/en/how-do-i-create-a-mycnf-mysql-preference-file.html
. And make sure you set the permissions to go-rwx so that noone else can read your file.
Your bash history is not the biggest (or at least not the only) concern: if you run sql this way, anyone can see your password with a simple ps ax while your session is open! Instead use mysql -uroot -p without a password: then the mysql client will present a password prompt that nobody can sniff (unless they're standing over your shoulder, or have root on your computer, or something equally unpreventable).

Alternative ways to issue multiple commands on a remote machine using SSH?

It appears that in this question, the answer was to separate statements with semicolons. However that could become cumbersome if we get into complex scripting with multiple if statements and complex quoted strings. I would think.
I imagine another alternative would be to simply issue multiple SSH commands one after the other, but again that would be cumbersome, plus I'm not set up for public/private key authentication so this would be asking for passwords a bunch of times.
What I'd ideally like is much similar to the interactive shell experience: at one point in the script you ssh into#the_remote_server and it prompts for the password, which you type in (interactively) and then from that point on until your script issues the "exit" command, all commands in the script are interpreted on the remote machine.
Of course this doesn't work:
ssh user#host.com
cd some/dir/on/remote/machine
tar -xzf my_tarball.tgz
cd some/other/dir/on/remote
cp -R some_directory somewhere_else
exit
Is there another alternative? I suppose I could take that part right out of my script and stick it into a script on the remote host. Meh. Now I'm maintaining two scripts. Plus I want a little configuration file to hold defaults and other stuff and I don't want to be maintaining that in two places either.
Is there another solution?
Use a heredoc.
ssh user#host.com << EOF
cd some/dir/on/remote/machine
tar -xzf my_tarball.tgz
cd some/other/dir/on/remote
cp -R some_directory somewhere_else
EOF
Use heredoc syntax, like
ssh user#host.com <<EOD
cd some/dir/on/remote/machine
...
EOD
or pipe, like
echo "ls -al" | ssh user#host.com

Resources