<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>&#x2F;</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>Terminal</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="/skins/indigo_ingot.css?h=d429472afbb246441b1a" /><title>Andrew Wippler's Sketchpad - Terminal</title>
        <subtitle>Ideas, blog, etc. </subtitle>
    <link href="/tags/terminal/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="/tags/terminal/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2016-12-23T14:00:27+00:00</updated><id>/tags/terminal/atom.xml</id><entry xml:lang="en">
        <title>Easy unix epoch timestamps from CLI</title>
        <published>2016-12-23T14:00:27+00:00</published>
        <updated>2016-12-23T14:00:27+00:00</updated>
        <author>
            <name>Andrew Wippler</name>
        </author>
        <link rel="alternate" href="/2016-12-23-easy-unix-epoch-timestamps-from-cli/" type="text/html"/>
        <id>/2016-12-23-easy-unix-epoch-timestamps-from-cli/</id>
        
            <content type="html">&lt;p&gt;While working on various projects and ultimately the need for a Unix timestamp for expiring swift objects in OpenStack, I needed a quick way to convert past, present, and future timestamps to the Unix epoch. Traditionally, I went to google, searched for a Unix timestamp converter, and retrieved my seconds that way. Unfortunately in exams, you are not allowed to visit external websites.&lt;&#x2F;p&gt;
&lt;p&gt;If you know how to read documentation, you will already know that the &lt;code&gt;date&lt;&#x2F;code&gt; command has this feature already built in. An excerpt from the docs is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; ...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       Show the local time for 9AM next Friday on the west coast of the US
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;              $ date --date=&amp;#39;TZ=&amp;quot;America&#x2F;Los_Angeles&amp;quot; 09:00 next Fri&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DATE STRING
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       The  --date=STRING  is  a mostly free format human readable date string
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       such as &amp;quot;Sun, 29 Feb 2004 16:21:42 -0800&amp;quot; or &amp;quot;2004-02-29  16:21:42&amp;quot;  or
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       even  &amp;quot;next Thursday&amp;quot;.  A date string may contain items indicating cal‐
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       endar date, time of day, time zone, day of week, relative  time,  rela‐
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       tive date, and numbers.  An empty string indicates the beginning of the
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       day.  The date string format is more complex than is easily  documented
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       here but is fully described in the info documentation.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Further reading of the docs will point you in specifically formatting a return string by doing a &lt;code&gt;date +%s&lt;&#x2F;code&gt;. So when the time comes to expire an object from swift at 17:00 next Friday, you can do something like:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;swift post container file -H &#x27;X-Delete-On: &lt;&#x2F;code&gt;date +%s --date=&quot;17:00 next Friday&quot;&lt;code&gt;&#x27;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
</content>
        </entry><entry xml:lang="en">
        <title>Expect with expect</title>
        <published>2015-08-30T22:41:50+00:00</published>
        <updated>2015-08-30T22:41:50+00:00</updated>
        <author>
            <name>Andrew Wippler</name>
        </author>
        <link rel="alternate" href="/2015-08-30-expect-with-expect/" type="text/html"/>
        <id>/2015-08-30-expect-with-expect/</id>
        
            <content type="html">&lt;p&gt;Wouldn&#x27;t it be nice to program a script that expects a certain line of text then sends a predetermined string? How about copy your ssh id to 40 different RPi units without typing the command for every one? Expect is that sort of program we all have been dreaming about. Just look at this script:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;expect -f
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;set timeout 3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;set serv [lindex $argv 0];
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;spawn ssh-copy-id pi@$serv
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sleep 4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;expect &amp;quot;Are you sure you want to continue connecting (yes&#x2F;no)?&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;send &amp;quot;yes\r&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;expect &amp;quot;pi@{$serv}&amp;#39;s password: &amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;send &amp;quot;p@ssw0rd\r&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;interact
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When this block of code is saved as &lt;code&gt;copy_pi.sh&lt;&#x2F;code&gt; and invoked as &lt;code&gt;.&#x2F;copy_pi.sh 192.168.1.42&lt;&#x2F;code&gt;, it will attemp to connect as the pi user, copy the current public key, say yes to the prompt, send the password (provided it is escaped properly), and drop you into the process you spawned.&lt;&#x2F;p&gt;
&lt;p&gt;Now, let&#x27;s look at the script in more detail as to what expect has to offer.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;expect -f
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This line has to be the absolute path of expect with the &lt;code&gt;-f&lt;&#x2F;code&gt; switch. This is to tell the program that it is being passed a file with a list of commands. On Debian&#x2F;Fedora, this path is where &lt;code&gt;expect&lt;&#x2F;code&gt; is located. On other systems, you will need to run &lt;code&gt;which expect&lt;&#x2F;code&gt; to find the absolute location.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;set timeout 3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;set serv [lindex $argv 0];
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first line tells &lt;code&gt;expect&lt;&#x2F;code&gt; to wait up to 3 seconds for a new line before it times out. The second line is grabbing the variable being passed into this script. Normally, one would think arg 0 would be the name of the program (i.e. &lt;code&gt;copy_pi.sh&lt;&#x2F;code&gt;); however, &lt;code&gt;expect&lt;&#x2F;code&gt; captures the variables into &lt;code&gt;$argv&lt;&#x2F;code&gt; (&lt;code&gt;$argc&lt;&#x2F;code&gt; is the length of the variables).You can also specify a range of variables into one: &lt;code&gt;set range [lrange $argv 0 2];&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;spawn ssh-copy-id pi@$serv
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sleep 4
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is we are initializing the process of copying our ssh key to &lt;code&gt;$serv&lt;&#x2F;code&gt;.
This is the part we would normally be typing ourselves. &lt;code&gt;sleep 4&lt;&#x2F;code&gt; tells expect to wait 4 seconds before continuing.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;expect &amp;quot;Are you sure you want to continue connecting (yes&#x2F;no)?&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;send &amp;quot;yes\r&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;expect &amp;quot;pi@{$serv}&amp;#39;s password: &amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;send &amp;quot;p@ssw0rd\r&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;interact
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;expect&lt;&#x2F;code&gt; line could either be regex or what will be exactly shown. Since I know exactly what will appear in the process, I have chosen to go that route. The &lt;code&gt;send&lt;&#x2F;code&gt; command is transmitting the text into the spawned program. Special characters such as &amp;amp; need to be escaped with a backslash. The &lt;code&gt;\r&lt;&#x2F;code&gt; simulates a carriage return (enter key). Since the &lt;code&gt;ssh-copy-id&lt;&#x2F;code&gt; is completed by the time &lt;code&gt;interact&lt;&#x2F;code&gt; is called, you will not be in the remote pi&#x27;s shell. I have sometimes found it necessary to include &lt;code&gt;interact&lt;&#x2F;code&gt; so that the password is actually sent.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;expect&lt;&#x2F;code&gt; is a great tool that uses TCL syntax. &lt;code&gt;expect&lt;&#x2F;code&gt; has prooved useful to me many times over - especially when I had to re-key my puppet deployment after Heartbleed.&lt;&#x2F;p&gt;
</content>
        </entry><entry xml:lang="en">
        <title>Send Aliases over SSH connections</title>
        <published>2015-07-18T22:12:35+00:00</published>
        <updated>2015-07-18T22:12:35+00:00</updated>
        <author>
            <name>Andrew Wippler</name>
        </author>
        <link rel="alternate" href="/2015-07-18-send-aliases-over-ssh-connections/" type="text/html"/>
        <id>/2015-07-18-send-aliases-over-ssh-connections/</id>
        
            <content type="html">&lt;p&gt;Bash reads aliases from a file only; however, this file does not have to reside on the server you are connecting to. With OpenSSH, we have to ability to send environment variables that the server allows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;On Debian&#x2F;Ubuntu systems, the default accept environment variables are:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Allow client to pass locale environment variables
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AcceptEnv LANG LC_*
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;On CentOS&#x2F;Fedora systems, the default accept environment variables are:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Accept locale-related environment variables
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AcceptEnv XMODIFIERS
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you remote into a mixed environment of servers - whether they be Debian, Ubuntu, or CentOS, you will need to find a common &lt;code&gt;AcceptEnv&lt;&#x2F;code&gt; variable. Since Debian and Ubuntu allow LC_* (everything with the prefix LC_), we are limited to forwarding our aliases over one of CentOS&#x27;s variables. For me, it was easy to decide on a variable to overwrite - &lt;code&gt;LC_PAPER&lt;&#x2F;code&gt;. I hardly print anything and I especially do not print on remote servers.&lt;&#x2F;p&gt;
&lt;p&gt;In order to send your aliases into a remote server, you have to set up your environment first.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;~&#x2F;.ssh&#x2F;config&lt;&#x2F;code&gt;, you need a line that sends the environment variable of your choice. These two lines denote that for every host, we will send the environment variable.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host *
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;     SendEnv LC_PAPER
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we will have to set an alias file we want to transfer. For my test, I create &lt;code&gt;~&#x2F;.bash_aliases_xfer&lt;&#x2F;code&gt; and had the contents of:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# .bash_aliases_xfer
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Source global definitions
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;if [ -f &#x2F;etc&#x2F;bashrc ]; then
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    . &#x2F;etc&#x2F;bashrc
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;alias lollypop=&amp;quot;echo lollypop&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;alias lolp=&amp;quot;lollypop&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;#My servers display useful information in the motd.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[ ! -z &amp;quot;$TERM&amp;quot; -a -r &#x2F;etc&#x2F;motd ] &amp;amp;&amp;amp; cat &#x2F;etc&#x2F;motd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we have to craft our ssh command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;LC_PAPER=$(cat ~&#x2F;.bash_aliases_xfer; exec 3&amp;lt;&amp;amp;-) \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssh -t user@remote \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;#39;exec bash --rcfile &#x2F;dev&#x2F;fd&#x2F;3 3&amp;lt; &amp;lt;(printf %s &amp;quot;$LC_PAPER&amp;quot;)&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first line defines the environment variable - an output of our local file and places that information in file descriptor 3. The second line is where we actually connect to the server. The third line is the command executed on the remote server: cleanly print the contents of our environment variable, put that information in file descriptor 3, and reload bash with that file as the only configuration file.&lt;&#x2F;p&gt;
&lt;p&gt;To make the process easier, I have place the following function in my .bashrc. Since the function has $@ variable, I can use it as a replacement to ssh and I can pass any needed ssh switches to my new function.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;function ssha() {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;LC_BASHRC=$(cat ~&#x2F;.bash_aliases_xfer; exec 3&amp;lt;&amp;amp;-) ssh -t &amp;quot;$@&amp;quot; &amp;#39;exec bash --rcfile &#x2F;dev&#x2F;fd&#x2F;3 3&amp;lt; &amp;lt;(printf %s &amp;quot;$LC_BASHRC&amp;quot;)&amp;#39;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After I reload my bashrc ( &lt;code&gt;source ~&#x2F;.bashrc&lt;&#x2F;code&gt; ), I can then pass my aliases into my new ssh session: &lt;code&gt;ssha user@remote -i ~&#x2F;.ssh&#x2F;remote_id -X&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
</content>
        </entry>
</feed>
