<?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 🍃 - shell</title>
    <link>https://emresahin.net/categories/shell/</link>
    <description>Posts in the shell 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/shell/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>bits 17</title>
      <published>2025-09-28T17:20:37+00:00</published>
      <updated>2025-09-28T17:20:37+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sun, 28 Sep 2025 17:20:37 +0000</pubDate>
      <link>https://emresahin.net/bits-17/</link>
      <guid isPermaLink="true">https://emresahin.net/bits-17/</guid>
      <description>I wanted to calculate the number of words added between commits in my blog posts. I asked Gemini for a Nushell pipeline based on git diff : It proposed the following: git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length H...</description>
      <category>shell</category>
      <category>productivity</category>
      <category>Gemini</category>
      <category>nushell</category>
      <category>git</category>
      <category>regex</category>
      <category>ai</category>
      <content:encoded><![CDATA[<p>I wanted to calculate the number of words added between commits in my blog posts. I asked Gemini for a Nushell pipeline based on <code>git diff</code>:</p>
<p>It proposed the following:</p>
<pre><code class="language-nushell">git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length
</code></pre>
<p>However, I ended up using this simplified version:</p>
<pre><code class="language-nushell">git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length
</code></pre>
<p>I’ve noticed that LLMs often lean toward overly complex solutions. I’m not sure if this is due to being trained to generate as many tokens as possible, but using regular expressions where a simple string replacement would suffice is often a sign of unnecessary complexity.</p>]]></content:encoded>
    </item>
    <item>
      <title>devlog 31</title>
      <published>2025-06-07T10:29:03+00:00</published>
      <updated>2025-06-07T10:29:03+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sat, 07 Jun 2025 10:29:03 +0000</pubDate>
      <link>https://emresahin.net/devlog-31/</link>
      <guid isPermaLink="true">https://emresahin.net/devlog-31/</guid>
      <description>🐢 I think sending Alt keys in Ghostty needs some love. Let’s start with it as an easy task for the day. 🐇 While checking macos-option-as-alt as a potential source of the problem, I spent time adjusting the Ghostty icon . I changed the app icon. This is how I spend my time being extremely producti...</description>
      <category>shell</category>
      <category>tmux</category>
      <category>ghostty</category>
      <category>productivity</category>
      <category>macos</category>
      <category>terminal</category>
      <content:encoded><![CDATA[<p>🐢 I think sending Alt keys in Ghostty needs some love. Let’s start with it as an easy task for the day.</p>
<p>🐇 While checking <a href="https://ghostty.org/docs/config/reference#macos-option-as-alt"><code>macos-option-as-alt</code></a> as a potential source of the problem, I spent time <a href="https://ghostty.org/docs/config/reference#macos-icon">adjusting the Ghostty icon</a>. I changed the app icon. This is how I spend my time being extremely productive.</p>
<p>🐢 Weird. The <code>Option as alt</code> key setting is fine.</p>
<p>🐇 Actually, the Alt key works; the reason we cannot make panes larger is that <code>Alt-Right</code> and <code>Alt-Left</code> are not bound to this.</p>
<p>🐢 You may be right, yes. Then, what’s the key to enlarge a pane?</p>
<p>🦊 List all the keys. Check the keys. You should have done this already.</p>
<pre><code class="language-shell">$ tmux list-keys | rg resize

bind-key    -T prefix       &gt;                      display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -x P -y P "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" &lt; { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" &gt; { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{&gt;:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{&gt;:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{&gt;:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z }
bind-key    -T prefix       z                      resize-pane -Z
bind-key -r -T prefix       M-Up                   resize-pane -U 5
bind-key -r -T prefix       M-Down                 resize-pane -D 5
bind-key -r -T prefix       M-Left                 resize-pane -L 5
bind-key -r -T prefix       C-Up                   resize-pane -U
bind-key -r -T prefix       C-Down                 resize-pane -D
bind-key -r -T prefix       C-Left                 resize-pane -L
bind-key -r -T prefix       C-Right                resize-pane -R
bind-key    -T root         MouseDown3Pane         if-shell -F -t = "#{||:#{mouse_any_flag},#{&amp;&amp;:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}" { select-pane -t = ; send-keys -M } { display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -t = -x M -y M "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" &lt; { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" &gt; { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{&gt;:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{&gt;:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{&gt;:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z } }
bind-key    -T root         MouseDrag1Border       resize-pane -M
bind-key    -T root         M-MouseDown3Pane       display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -t = -x M -y M "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" &lt; { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" &gt; { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{&gt;:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{&gt;:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{&gt;:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z }
</code></pre>
<p>🐇 <code>resize-pane</code> has keys, but they conflict with <code>C-Right</code>, etc., which are macOS display selection keys. I defined <code>M-S-Right</code>, etc., to resize and <code>M-C-Right</code>, etc., to swap the panes. Defining new keys with <code>M-S</code>…</p>
<pre><code class="language-tmux">bind-key -n "M-S-Right" resize-pane -R 10
bind-key -n "M-S-Left" resize-pane -L 10
bind-key -n "M-S-Up" resize-pane -U 10
bind-key -n "M-S-Down" resize-pane -D 10
</code></pre>
<p>🐢 We can set keys to swap windows too, maybe to <code>M-C-PageDown</code>, etc. <code>M-PageDown</code> now moves between windows.</p>
<p>🐇 Let’s take a look at the command options:</p>
<pre><code class="language-text">     swap-window [-d] [-s src-window] [-t dst-window]
                   (alias: swapw)
             This is similar to link-window, except the source and destination windows are swapped.  It is an error if no window exists at src-window.  If -d is given, the new window
             does not become the current window.

             If -s is omitted and a marked pane is present (see select-pane -m), the window containing the marked pane is used rather than the current window.
</code></pre>
<p>🐢 The use case will be limited, though.</p>
<p>🐇 Umm, right. Let’s stop procrastinating here.</p>
<p>🐢 It was productive procrastination, though. Now I can resize my tmux panes.</p>]]></content:encoded>
    </item>
    <item>
      <title>Nushell $env.PATH in tmux</title>
      <published>2025-05-30T16:09:29+00:00</published>
      <updated>2025-05-30T16:09:29+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Fri, 30 May 2025 16:09:29 +0000</pubDate>
      <link>https://emresahin.net/nushell--env-path-in-tmux/</link>
      <guid isPermaLink="true">https://emresahin.net/nushell--env-path-in-tmux/</guid>
      <description>I noticed that when I use: set -g default-shell nu in .tmux.conf to specify Nushell as the shell, it doesn’t load $env.PATH . It is necessary to specify the shell with: set -g default-command nu -l (using the full path to nu ) to ensure the shell reads your configuration file.</description>
      <category>Shell</category>
      <category>Nushell</category>
      <category>Tmux</category>
      <category>Terminal</category>
      <category>Configuration</category>
      <content:encoded><![CDATA[<p>I noticed that when I use:</p>
<pre><code class="language-tmux">set -g default-shell nu
</code></pre>
<p>in <code>.tmux.conf</code> to specify Nushell as the shell, it doesn’t load <code>$env.PATH</code>. It is necessary to specify the shell with:</p>
<pre><code class="language-tmux">set -g default-command nu -l
</code></pre>
<p>(using the full path to <code>nu</code>) to ensure the shell reads your configuration file.</p>]]></content:encoded>
    </item>
    <item>
      <title>bits 15</title>
      <published>2025-03-27T09:52:06+00:00</published>
      <updated>2025-03-27T09:52:06+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Thu, 27 Mar 2025 09:52:06 +0000</pubDate>
      <link>https://emresahin.net/bits-15/</link>
      <guid isPermaLink="true">https://emresahin.net/bits-15/</guid>
      <description>How to use a Python virtual environment with Nushell: virtualenv .venv overlay use .venv/bin/activate.nu</description>
      <category>bits</category>
      <category>shell</category>
      <category>nushell</category>
      <category>Python</category>
      <category>venv</category>
      <category>virtualenv</category>
      <category>cli</category>
      <content:encoded><![CDATA[<p>How to use a Python virtual environment with Nushell:</p>
<pre><code class="language-nu">virtualenv .venv
overlay use .venv/bin/activate.nu
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>My Nushell aliases for `gh` command</title>
      <published>2025-01-29T08:04:19+00:00</published>
      <updated>2025-01-29T08:04:19+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Wed, 29 Jan 2025 08:04:19 +0000</pubDate>
      <link>https://emresahin.net/my-nushell-aliases-for--gh--command/</link>
      <guid isPermaLink="true">https://emresahin.net/my-nushell-aliases-for--gh--command/</guid>
      <description>Almost every day, I start my work by playing with my configuration. Today, I added aliases for gh (GitHub CLI) to Nushell. # List issues related to me export def ghil [] { (gh issue list --search "involves:iesahin" --json title,url) | from json } # Add a comment to an issue export alias ghic = gh...</description>
      <category>Shell</category>
      <category>Nushell</category>
      <category>nushell</category>
      <category>gh</category>
      <category>GitHub</category>
      <category>CLI</category>
      <content:encoded><![CDATA[<p>Almost every day, I start my work by playing with my configuration. Today, I added aliases for <code>gh</code> (GitHub CLI) to Nushell.</p>
<pre><code class="language-nu"># List issues related to me
export def ghil [] { 
  (gh issue list --search "involves:iesahin" --json title,url) | from json
}

# Add a comment to an issue
export alias ghic = gh issue comment

# Create an issue
export alias ghiC = gh issue create $in

# View an issue
export alias ghiv = gh issue view

# View an issue in the browser
export alias ghiw = gh issue view --web

# List PRs in a table
export def ghpl [] {
  (gh pr list --json "title,url,headRefName" ) | from json
}

# View a PR
export alias ghpv = gh pr view

# View a PR in GitHub
export alias ghpw = gh pr view --web

# Checkout a PR
export alias ghco = gh pr checkout

# Add a comment to a PR
export alias ghpc = gh pr comment

# Show changes in a PR
export alias ghpd = gh pr diff

# Add a review to a PR
export alias ghpR = gh pr review

# Create a PR
export alias ghpC = gh pr create

# Merge a PR to main
export alias ghpM = gh pr merge

# List GH CI runs in a table
export def ghrl [] {
  (gh run list --json conclusion,displayTitle,headBranch,url ) | from json 
}

# View a GH CI run
export alias ghrv = gh run view

# View a GH CI run in the browser
export alias ghrw = gh run view --web 

# View output from a failed run
export alias ghrf = gh run view --log-failed

# Search code and get results in a table
export def ghsc [] { 
  (gh search code $in --json repository,path,textMatches,url) | from json
}
</code></pre>
<p>Aliases don’t allow pipes in Nushell, so I used <code>def</code> for those that require them.</p>
<p>When there is an <code>$in</code> parameter in an alias, it expects the input from a pipe.
An issue can be created like this, for example:</p>
<pre><code class="language-nu">"Your software sucks" | ghiC
</code></pre>
<p>To search for the code copied to the clipboard and get only the URLs, you can use:</p>
<pre><code class="language-nu">pbpaste | ghsc | get url
</code></pre>
<p>To open them in different browser windows:</p>
<pre><code class="language-nu">pbpaste | ghsc | get url | each { |u| start $u }
</code></pre>
<p>I’ll add a shortcut key for this last one. It’s so quick! :D</p>]]></content:encoded>
    </item>
    <item>
      <title>Merging all Tmux windows in a single session</title>
      <published>2024-06-12T21:24:15+00:00</published>
      <updated>2024-06-12T21:24:15+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Wed, 12 Jun 2024 21:24:15 +0000</pubDate>
      <link>https://emresahin.net/merging-all-tmux-windows-in-a-single-session/</link>
      <guid isPermaLink="true">https://emresahin.net/merging-all-tmux-windows-in-a-single-session/</guid>
      <description>I use a new Tmux session for each day. Over time, I noticed that sessions proliferate, and I often need windows from earlier sessions in a central location. This script merges all windows from all Tmux sessions into a single session. You must specify the target session as a parameter. If you save...</description>
      <category>Shell</category>
      <category>Terminal</category>
      <category>Tmux</category>
      <category>Script</category>
      <category>Zsh</category>
      <category>Automation</category>
      <category>Productivity</category>
      <content:encoded><![CDATA[<p>I use a new Tmux session for each day. Over time, I noticed that sessions proliferate, and I often need windows from earlier sessions in a central location.</p>
<p>This script merges all windows from all Tmux sessions into a single session. You must specify the target session as a parameter. If you save the script as <code>merge-tmux-sessions.zsh</code>, you can run it like:</p>
<pre><code class="language-bash">merge-tmux-sessions.zsh my-current-session
</code></pre>
<p>It will then move all windows into the session you specify.</p>
<pre><code class="language-zsh">#!/bin/zsh

# set -vuex
#
#  Specify the target session

target_session=$1

# Get the list of all sessions

sessions=$(tmux list-sessions -F '#S')

# Iterate through each session

for session in ${(@f)sessions}; do
    if [ "$session" != "$target_session" ]; then
        # Get the list of windows in the current session
        windows=$(tmux list-windows -t $session -F '#I')

        # Move each window to the target session
        for window in ${(@f)windows}; do
            tmux move-window -s ${session}:${window} -t ${target_session}
        done
    fi

done
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>TIL: Get the Latest Git Commit SHA-1</title>
      <published>2024-02-13T09:58:12+00:00</published>
      <updated>2024-02-13T09:58:12+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Tue, 13 Feb 2024 09:58:12 +0000</pubDate>
      <link>https://emresahin.net/til-6/</link>
      <guid isPermaLink="true">https://emresahin.net/til-6/</guid>
      <description>This command retrieves the SHA-1 hash of the latest commit: git rev-parse HEAD</description>
      <category>Shell</category>
      <category>Version Control</category>
      <category>Git</category>
      <category>CLI</category>
      <category>SHA-1</category>
      <content:encoded><![CDATA[<p>This command retrieves the SHA-1 hash of the latest commit:</p>
<pre><code class="language-bash">git rev-parse HEAD
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>bits 11</title>
      <published>2020-12-26T01:07:01+00:00</published>
      <updated>2020-12-26T01:07:01+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sat, 26 Dec 2020 01:07:01 +0000</pubDate>
      <link>https://emresahin.net/bits-11/</link>
      <guid isPermaLink="true">https://emresahin.net/bits-11/</guid>
      <description>Awk is executed using awk 'awk_program' data-file . Awk programs follow the form pattern { action }; pattern { action }; . BEGIN blocks are executed before reading the data files. END blocks are executed after reading the data files. NR is a variable that indicates the number of records (rows) re...</description>
      <category>shell</category>
      <category>tooling</category>
      <category>awk</category>
      <category>linux</category>
      <category>gawk</category>
      <content:encoded><![CDATA[<ul>
<li>Awk is executed using <code>awk 'awk_program' data-file</code>.</li>
<li>Awk programs follow the form <code>pattern { action }; pattern { action };</code>.</li>
<li><code>BEGIN</code> blocks are executed before reading the data files.</li>
<li><code>END</code> blocks are executed after reading the data files.</li>
<li><code>NR</code> is a variable that indicates the number of records (rows) read so far.</li>
<li><code>-F '&lt;separator&gt;'</code> is used to define a field separator for a file.</li>
<li>A space is the default field separator.</li>
<li><code>FPAT</code> is a regex used to define the pattern for each field.</li>
<li><code>FPAT</code> is specifically defined in Gawk.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Zenity</title>
      <published>2018-12-03T18:54:26+00:00</published>
      <updated>2018-12-03T18:54:26+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Mon, 03 Dec 2018 18:54:26 +0000</pubDate>
      <link>https://emresahin.net/zenity-14386-18029/</link>
      <guid isPermaLink="true">https://emresahin.net/zenity-14386-18029/</guid>
      <description>When you need a simple dialog to get input from a user or display information in a GUI dialog box, zenity is a great tool. It allows shell scripts to interact with users through various types of dialogs. zenity --info --text="Merge complete. Updated 3 of 10 files."</description>
      <category>shell</category>
      <category>tool</category>
      <category>zenity</category>
      <category>bash</category>
      <category>shell</category>
      <category>linux</category>
      <category>gui</category>
      <content:encoded><![CDATA[<p>When you need a simple dialog to get input from a user or display information in a GUI dialog box, <a href="https://help.gnome.org/users/zenity/3.24/"><code>zenity</code></a> is a great tool. It allows shell scripts to interact with users through various types of dialogs.</p>
<pre><code class="language-bash">zenity --info --text="Merge complete. Updated 3 of 10 files."
</code></pre>
<p><img src="https://emresahin.net/images/zenity-ss.png" alt="zenity-ss"></p>]]></content:encoded>
    </item>
    <item>
      <title>Copying and pasting with XWindow clipboard from tmux</title>
      <published>2013-01-12T14:00:00+00:00</published>
      <updated>2013-01-12T14:00:00+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sat, 12 Jan 2013 14:00:00 +0000</pubDate>
      <link>https://emresahin.net/12235-5-1945/</link>
      <guid isPermaLink="true">https://emresahin.net/12235-5-1945/</guid>
      <description>tmux does not natively support XWindow’s clipboard. With two lines in .tmux.conf , you can configure two keys to send and retrieve clipboard content. Traditionally, applications use the PRIMARY selection, which uses the mouse selection for copying and pasting with the middle mouse button. However...</description>
      <category>Shell</category>
      <category>Linux</category>
      <category>tmux</category>
      <category>xwindow</category>
      <category>copy</category>
      <category>paste</category>
      <category>clipboard</category>
      <category>xsel</category>
      <content:encoded><![CDATA[<p><code>tmux</code> does not natively support XWindow’s clipboard. With two lines in
<code>.tmux.conf</code>, you can configure two keys to send and retrieve clipboard
content.</p>
<p>Traditionally, applications use the <code>PRIMARY</code> selection, which uses the mouse
selection for copying and pasting with the middle mouse button. However, this
is becoming less common, so I’ll configure the <code>CLIPBOARD</code>
selection used by most modern browsers, applications, and Emacs.</p>
<p>Add the following lines to <code>.tmux.conf</code>:</p>
<pre><code class="language-bash"># move x clipboard into tmux paste buffer
bind &lt; run "xsel -ob | tmux load-buffer - ; tmux paste-buffer "
# move tmux copy buffer into x clipboard
bind &gt; run "( tmux show-buffer | xsel -bi ) &amp;&amp; tmux display-message \"ok!\""
</code></pre>
<p>The first line sets <code>C-b &lt;</code> in <code>tmux</code> to retrieve the X clipboard contents
and paste them. The second line sets <code>C-b &gt;</code> to send the current <code>tmux</code> buffer to
the X clipboard for pasting into another application.</p>
<p>If you would still like to use the <code>PRIMARY</code> selection, you can drop the <code>b</code> options
from <code>xsel</code>, using <code>xsel -o</code> and <code>xsel -i</code> respectively.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
