<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>emre şahin's digital garden 🍃 - CLI</title>
    <link>https://emresahin.net/categories/cli/</link>
    <description>Posts in the CLI category</description>
    <language>en</language>
    <managingEditor>contact@emresahin.net (Emre Şahin)</managingEditor>
    <lastBuildDate>Tue, 15 Sep 2026 19:46:32 +0000</lastBuildDate>
    <atom:link href="https://emresahin.net/categories/cli/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Activate left window when the current one is closed in tmux</title>
      <published>2022-02-16T07:08:25+00:00</published>
      <updated>2022-02-16T07:08:25+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Wed, 16 Feb 2022 07:08:25 +0000</pubDate>
      <link>https://emresahin.net/Activate-left-window-when-the-current-one-is-closed-in-tmux/</link>
      <guid isPermaLink="true">https://emresahin.net/Activate-left-window-when-the-current-one-is-closed-in-tmux/</guid>
      <description>When I close a window in tmux, it typically activates the window to its right. I prefer the previously active window to be activated instead. I couldn’t find a direct setting for this, but tmux provides hooks for various events. By setting the window-unlinked hook to trigger last-window , I can a...</description>
      <category>CLI</category>
      <category>Tools</category>
      <category>tmux</category>
      <category>configuration</category>
      <category>hooks</category>
      <category>productivity</category>
      <content:encoded><![CDATA[<p>When I close a window in tmux, it typically activates the window to its right. I
prefer the previously active window to be activated instead. I couldn’t find a
direct setting for this, but tmux provides <a href="https://man7.org/linux/man-pages/man1/tmux.1.html#HOOKS">hooks</a>
for various events. By setting the <code>window-unlinked</code> hook to trigger <code>last-window</code>,
I can achieve the desired behavior.</p>
<p>Add the following to your <code>.tmux.conf</code>:</p>
<pre><code class="language-conf">set-hook -g window-unlinked 'last-window'
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>TIL: sed</title>
      <published>2020-07-15T15:51:00+00:00</published>
      <updated>2020-07-15T15:51:00+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Wed, 15 Jul 2020 15:51:00 +0000</pubDate>
      <link>https://emresahin.net/sed/</link>
      <guid isPermaLink="true">https://emresahin.net/sed/</guid>
      <description>When I try to use sed to find and edit multiple files, I always remember that perl -pe is better suited for this task. Today, this happened again. I tried to find and replace lines starting with # Bla bla with title: Bla bla , and it was easier to use perl -pe 's|^#+ (.*)|title: $1|g' than identi...</description>
      <category>CLI</category>
      <category>sed</category>
      <category>perl</category>
      <category>regex</category>
      <category>til</category>
      <content:encoded><![CDATA[<p>When I try to use <code>sed</code> to find and edit multiple files, I always remember that <code>perl -pe</code> is better suited for this task. Today, this happened again. I tried to find and replace lines starting with <code># Bla bla</code> with <code>title: Bla bla</code>, and it was easier to use <code>perl -pe 's|^#+ (.*)|title: $1|g'</code> than identifying what kind of regular expressions <code>sed</code> uses.</p>
<hr>
<p>It’s possible to get a section from a Markdown file with a command like:</p>
<pre><code class="language-bash">sed -n -e '/^#/,/^#/p'
</code></pre>
<p>It is also possible to use line numbers instead of regexes. The <code>p</code> at the end is the print command, which can be replaced by, for example, <code>d</code> to delete the lines.</p>]]></content:encoded>
    </item>
    <item>
      <title>telegram-send</title>
      <published>2020-05-12T18:47:24+00:00</published>
      <updated>2020-05-12T21:47:34+03:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Tue, 12 May 2020 18:47:24 +0000</pubDate>
      <link>https://emresahin.net/telegram-send-6932/</link>
      <guid isPermaLink="true">https://emresahin.net/telegram-send-6932/</guid>
      <description>A little Python CLI app for Telegram messages</description>
      <category>CLI</category>
      <category>Telegram</category>
      <category>Tools</category>
      <category>Python</category>
      <category>Automation</category>
      <category>Messaging</category>
      <category>Bot</category>
      <content:encoded><![CDATA[<p>There is a small Python command-line program called <code>telegram-send</code> that allows you to send messages to your
Telegram account.</p>
<p>First, you need to register a new bot with <a href="https://t.me/BotFather">@BotFather</a> and get an API token. Then,
run <code>pip3 install --user telegram-send</code> and prepare a config file at <code>~/.config/telegram-send.conf</code>:</p>
<pre><code class="language-ini">[telegram]
token = &lt;TOKEN_YOU_GET_FROM_BOT_FATHER&gt;
chat_id = &lt;CHAT_OR_USER_ID&gt;
</code></pre>
<p>You’ll need to start a conversation with the bot and find your user ID (which is identical to the chat
ID for the conversation you start with the bot).</p>
<p>After that, you can send yourself messages from the CLI like this:</p>
<pre><code class="language-bash">telegram-send "Hello Telegram."
</code></pre>
<p>You can also send Markdown-formatted messages, audio, stickers, and more using various command-line options:</p>
<pre><code class="language-text">usage: telegram-send [-h] [--format {text,markdown,html}] [--stdin] [--pre]
                     [--disable-web-page-preview] [--silent] [-c]
                     [--configure-channel] [--configure-group]
                     [-f FILE [FILE ...]] [-i IMAGE [IMAGE ...]]
                     [-s STICKER [STICKER ...]]
                     [--animation ANIMATION [ANIMATION ...]]
                     [--video VIDEO [VIDEO ...]] [--audio AUDIO [AUDIO ...]]
                     [-l LOCATION [LOCATION ...]]
                     [--caption CAPTION [CAPTION ...]] [--config CONF] [-g]
                     [--file-manager] [--clean] [--timeout TIMEOUT]
                     [--version]
                     [message [message ...]]
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Backup Script for Recent Files</title>
      <published>2014-02-01T22:00:00+00:00</published>
      <updated>2014-02-01T22:00:00+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sat, 01 Feb 2014 22:00:00 +0000</pubDate>
      <link>https://emresahin.net/backup-script-for-recent-files/</link>
      <guid isPermaLink="true">https://emresahin.net/backup-script-for-recent-files/</guid>
      <description>I decided to write a script to back up only recent files. There are solutions based on unison that work periodically for all files, but as I change projects, I need to configure new backups for these projects as well. This is cumbersome and error-prone; it is easy to forget to add new artifacts t...</description>
      <category>cli</category>
      <category>tools</category>
      <category>devops</category>
      <category>backup</category>
      <category>rsync</category>
      <category>unison</category>
      <category>bash</category>
      <category>script</category>
      <category>cron</category>
      <category>linux</category>
      <category>automation</category>
      <content:encoded><![CDATA[<p>I decided to write a script to back up only recent files. There are solutions based on <a href="http://www.cis.upenn.edu/~bcpierce/unison/">unison</a> that work periodically for all files, but as I change projects, I need to configure new backups for these projects as well. This is cumbersome and error-prone; it is easy to forget to add new artifacts to backup scripts and lose them in an emergency.</p>
<p>Therefore, I decided that a small Bash script using <a href="http://rsync.samba.org/">rsync</a> and <a href="http://en.wikipedia.org/wiki/Find">find</a> would work better. It monitors my entire home directory and backs up recent files.</p>
<p>The following script does exactly that:</p>
<pre><code class="language-bash">#!/bin/bash

if [ "x$1" = "x" ] ; then
    TARGET=/media/augustus/backup-recent-`hostname`
else
    TARGET=$1
fi

PERIOD=15

mkdir -p $TARGET

# Delete files older than $PERIOD days
find $TARGET -ctime +$PERIOD -print -delete

# Copy files newer than $PERIOD under ~. Ignore files under .hg
for d in ~/*/ ; do
    find $d -path '*/.hg/*' -prune -o -type f -ctime -$PERIOD -print  -exec rsync -aRv {} $TARGET/ \;
done
</code></pre>
<p>It checks whether a command-line option is provided as the target; otherwise, it sets a default target. <code>/media/augustus/</code> is an NFS mount in my case, but you can specify any path.</p>
<p><code>PERIOD</code> is the number of days that the script considers <em>recent</em>. Currently, it backs up files changed in the last 15 days.</p>
<p>The script deletes older files from the backup. Since I use other solutions for long-term storage, I don’t want to keep them here, especially since this script runs via <code>cron</code> every two hours.</p>
<p>Note that the script only checks directories under the home directory, so files located directly in the home directory are not backed up.</p>
<p>It also skips files under <code>.hg</code> directories. You can add more <code>-prune</code> options to the <code>find</code> command to exclude other irrelevant directories from your backup.</p>]]></content:encoded>
    </item>
    <item>
      <title>Shell (Bash and Zsh) Notes</title>
      <published>2013-08-16T21:00:00+00:00</published>
      <updated>2013-08-16T21:00:00+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Fri, 16 Aug 2013 21:00:00 +0000</pubDate>
      <link>https://emresahin.net/shell-notes/</link>
      <guid isPermaLink="true">https://emresahin.net/shell-notes/</guid>
      <description>Don’t use ~ in scripts; use $HOME I have used ~ several times in scripts, but it may not always expand as expected depending on the environment. Use $HOME to refer to the home directory; it is much more reliable and always works.</description>
      <category>Scripting</category>
      <category>CLI</category>
      <category>shell</category>
      <category>bash</category>
      <category>zsh</category>
      <category>scripting</category>
      <category>best practices</category>
      <category>til</category>
      <content:encoded><![CDATA[<h1 id="dont-use--in-scripts-use-home">Don’t use <code>~</code> in scripts; use <code>$HOME</code></h1>
<p>I have used <code>~</code> several times in scripts, but it may not always expand as expected depending on the environment. Use <code>$HOME</code> to refer to the home directory; it is much more reliable and always works.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
