<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Florian Stolzenhain</title>
    <description>The latest articles on DEV Community by Florian Stolzenhain (@stolzenhain).</description>
    <link>https://dev.to/stolzenhain</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1182123%2F7a03fd1a-bc05-4813-b988-3e7e4dedd9f0.png</url>
      <title>DEV Community: Florian Stolzenhain</title>
      <link>https://dev.to/stolzenhain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stolzenhain"/>
    <language>en</language>
    <item>
      <title>Bulk-create editor users in Drupal by mail address</title>
      <dc:creator>Florian Stolzenhain</dc:creator>
      <pubDate>Fri, 14 Feb 2025 15:03:41 +0000</pubDate>
      <link>https://dev.to/stolzenhain/programmatically-creating-editor-users-in-drupal-by-mail-address-36hn</link>
      <guid>https://dev.to/stolzenhain/programmatically-creating-editor-users-in-drupal-by-mail-address-36hn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://studioagenturbuero.com/archive/2023/drush-create-users/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt; on my blog, happy to include feedback!&lt;br&gt;
Cover: &lt;a href="https://www.flickr.com/photos/biblarte/" rel="noopener noreferrer"&gt;Biblioteca de Arte / Art Library Fundação Calouste Gulbenkian&lt;/a&gt;, via &lt;a href="https://nos.twnsnd.co/post/697378684450013184/f%C3%A1brica-de-chocolates-regina-lisboa-portugal" rel="noopener noreferrer"&gt;New Old Stock&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This creates a user according to it's email, sets a role and creates a 24h valid one-time-login.&lt;br&gt;
The link can be transmitted for easy setup of password and account settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drush user-create &lt;span class="o"&gt;[&lt;/span&gt;username] &lt;span class="nt"&gt;--mail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[user@mail]"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
    drush user-add-role &lt;span class="s2"&gt;"[editor]"&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;username] &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
    drush uli &lt;span class="nt"&gt;--uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[https://example.com]"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[username]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For adding a role to multiple users, use comma separated arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drush user-add-role &lt;span class="s2"&gt;"[editor]"&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;username1,username2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.drush.org/13.3.0/commands/user_create/" rel="noopener noreferrer"&gt;drush user-create&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drush.org/13.3.0/commands/user_role_add/" rel="noopener noreferrer"&gt;drush user-add-role&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drush.org/13.3.0/commands/user_login/" rel="noopener noreferrer"&gt;drush uli – note &lt;code&gt;uri&lt;/code&gt; param to generate correct URLs via shell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>drupal</category>
      <category>automation</category>
      <category>shell</category>
      <category>cheatsheet</category>
    </item>
    <item>
      <title>HTML whitespace control</title>
      <dc:creator>Florian Stolzenhain</dc:creator>
      <pubDate>Tue, 04 Feb 2025 16:56:04 +0000</pubDate>
      <link>https://dev.to/stolzenhain/html-whitespace-control-36b5</link>
      <guid>https://dev.to/stolzenhain/html-whitespace-control-36b5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://studioagenturbuero.com/archive/2023/whitespace-control/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt; on my blog, happy to include feedback!&lt;br&gt;
Cover: &lt;a href="https://www.flickr.com/photos/nasacommons/9458244245/" rel="noopener noreferrer"&gt;NASA&lt;/a&gt;, via &lt;a href="https://nos.twnsnd.co/post/140452918848/orbital-sunrise-with-venus-and-mars" rel="noopener noreferrer"&gt;New Old Stock&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Assuming you're wrangling with whitespace-critical code like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- will display an additional space character --&amp;gt;&lt;/span&gt;
    my link text
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you could either remove whitespace in your template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;my link text&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or use your templater's whitespace control:&lt;/p&gt;

&lt;h2&gt;
  
  
  Handlebars
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{!-- will remove whitespace on each side of the tilde --}}
    {{~ text ~}}
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;see also: &lt;a href="https://handlebarsjs.com/guide/expressions.html#whitespace-control" rel="noopener noreferrer"&gt;Expressions | Handlebars / Whitespace Control&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Twig
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {# remove whitespace on each side of the tilde #}
    {{- text -}}
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {# remove whitespace on each side of the tilde – not newlines #}
    {{~ text ~}}
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{# suppress whitespace in this region #}
{% spaceless %}
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ text }}
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
{% endspaceless %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;see also: &lt;a href="https://twig.symfony.com/doc/3.x/filters/spaceless.html" rel="noopener noreferrer"&gt;Twig – spaceless&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>templates</category>
      <category>twig</category>
      <category>handlebars</category>
    </item>
    <item>
      <title>Poor man's parallel in Bash</title>
      <dc:creator>Florian Stolzenhain</dc:creator>
      <pubDate>Fri, 10 Jan 2025 19:43:34 +0000</pubDate>
      <link>https://dev.to/stolzenhain/poor-mans-parallel-in-bash-46e2</link>
      <guid>https://dev.to/stolzenhain/poor-mans-parallel-in-bash-46e2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://studioagenturbuero.com/archive/2025/poor-mans-parallel/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt; on my blog, happy to include feedback!&lt;br&gt;
Cover: &lt;a href="https://bibliotheques-specialisees.paris.fr/ark:/73873/pf0002007312/v0153.simple.selectedTab=record.hidesidebar" rel="noopener noreferrer"&gt;Paris bibliothéques&lt;/a&gt;, via &lt;a href="https://clawmarks.tumblr.com/post/759909353842245632/raccolta-di-vignette-allegoriche-simboliche-e" rel="noopener noreferrer"&gt;Clawmarks&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Topics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Running scripts in parallel&lt;/li&gt;
&lt;li&gt;Tools to limit concurrent jobs&lt;/li&gt;
&lt;li&gt;Shell process handling cheatsheet&lt;/li&gt;
&lt;li&gt;Limit concurrent jobs with Bash&lt;/li&gt;
&lt;li&gt;Bonus: One-liners&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1) Running scripts in parallel
&lt;/h2&gt;

&lt;p&gt;does not take much effort: I've been speeding up builds by running commands simultaneously with an added &lt;code&gt;&amp;amp;&lt;/code&gt; ampersand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# stuff can happen concurrently&lt;/span&gt;
&lt;span class="c"&gt;# use `&amp;amp;` to run in a sub-shell&lt;/span&gt;
cmd1 &amp;amp;
cmd2 &amp;amp;
cmd3 &amp;amp;
&lt;span class="c"&gt;# wait on sub-processes&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;span class="c"&gt;# these need to happen sequentially&lt;/span&gt;
cmd3
cmd4

&lt;span class="nb"&gt;echo &lt;/span&gt;Done!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Job control is a shell feature: commands are put into a background process and run at the same time.&lt;/p&gt;

&lt;p&gt;Now assuming you want to loop over more than a few commands, e.g. converting files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c"&gt;# start optimizing every file at once&lt;/span&gt;
    jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="c"&gt;# finish queue&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running a lot of processes this way is still faster than a regular loop. But compared to just a few concurrent jobs there are no speed gains – even &lt;strong&gt;possible slowdowns&lt;/strong&gt; on async disk I/O [Quotation needed].&lt;/p&gt;

&lt;p&gt;So you'll want to use&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Tools to limit concurrent jobs
&lt;/h2&gt;

&lt;p&gt;by either 1) installing &lt;strong&gt;custom tools&lt;/strong&gt; like &lt;a href="https://www.gnu.org/software/parallel/" rel="noopener noreferrer"&gt;parallel&lt;/a&gt; or &lt;a href="http://www.maier-komor.de/xjobs.html" rel="noopener noreferrer"&gt;xjobs&lt;/a&gt; or 2) relying on &lt;strong&gt;xargs&lt;/strong&gt;, which is a feature-rich tool but more complicated.&lt;/p&gt;

&lt;p&gt;Transforming &lt;code&gt;wait&lt;/code&gt; to &lt;code&gt;xargs&lt;/code&gt; code is described here: &lt;a href="https://codemadness.org/xargs.html" rel="noopener noreferrer"&gt;an example for parallel batch jobs&lt;/a&gt;. The article notes small differences between POSIX flavours – e.g. different handling of separators on BSD/MacOS.&lt;/p&gt;

&lt;p&gt;We'll be choosing option 3) – digging into features of &lt;code&gt;wait&lt;/code&gt; and &lt;code&gt;jobs&lt;/code&gt; to &lt;strong&gt;manage processes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quoting &lt;a href="https://superuser.com/questions/1000165/bash-execute-when-job-in-background-completes/1001290#1001290" rel="noopener noreferrer"&gt;this great summary&lt;/a&gt;, here are some example commands for&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Shell process handling
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# run child process, save process id via `$!`&lt;/span&gt;
cmd3 &amp;amp; &lt;span class="nv"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;span class="c"&gt;# get job list&lt;/span&gt;
&lt;span class="nb"&gt;jobs&lt;/span&gt;
&lt;span class="c"&gt;# get job ids only&lt;/span&gt;
&lt;span class="c"&gt;# note: not available on zsh&lt;/span&gt;
&lt;span class="nb"&gt;jobs&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;span class="c"&gt;# only wait on job at position `n`&lt;/span&gt;
&lt;span class="c"&gt;# note: slots may turn up empty while&lt;/span&gt;
&lt;span class="c"&gt;#       newer jobs rest in the queue's tail&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt; %n
&lt;span class="c"&gt;# wait on last job in list&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt; %%
&lt;span class="c"&gt;# wait on next finishing process&lt;/span&gt;
&lt;span class="c"&gt;# note: needs Bash 4.3&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Taking our example from before, we make sure to&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Limit concurrent jobs with Bash
&lt;/h2&gt;

&lt;p&gt;each time a process is finished using &lt;code&gt;wait -n&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do

    &lt;/span&gt;jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;

    &lt;span class="c"&gt;# still &amp;lt; 3 max job -l ines? continue loop&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;jobs&lt;/span&gt;|wc &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; 3 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# with 3 jobs, wait for -n ext, then loop&lt;/span&gt;
    &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;

&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="c"&gt;# finish queue&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sadly, &lt;strong&gt;this won't work in MacOS&lt;/strong&gt;, because Bash environments are frozen on old versions. We replace the &lt;code&gt;wait -n&lt;/code&gt; command with &lt;code&gt;wait %%&lt;/code&gt; to loop on the 3rd/last job in queue – an ok compromise on small groups (1/3 chance of fastest/slowest/medium job):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do

    &lt;/span&gt;jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;

    &lt;span class="c"&gt;# still &amp;lt; 3 max job -l ines? continue loop&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;jobs&lt;/span&gt;|wc &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; 3 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# with 3 jobs, wait for last in line, then loop&lt;/span&gt;
    &lt;span class="nb"&gt;wait&lt;/span&gt; %%

&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="c"&gt;# finish queue&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To further develop the code, one could check for Bash version or alternative shells (zsh on MacOS) to switch code depending on context. I keep using these:&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Bonus: One-liners
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# sequential, slow&lt;/span&gt;
&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# concurrent, messy&lt;/span&gt;
&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp; &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# concurrent, fast/compatible&lt;/span&gt;
&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;jobs&lt;/span&gt;|wc &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; 3 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; %%&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# concurrent, fastest&lt;/span&gt;
&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;jpegoptim &lt;span class="nt"&gt;-m&lt;/span&gt; 45 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;jobs&lt;/span&gt;|wc &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; 3 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fun Fact
&lt;/h2&gt;

&lt;p&gt;As the &lt;a href="https://www.gnu.org/software/parallel/20th-birthday.html" rel="noopener noreferrer"&gt;20th birthday post&lt;/a&gt; by &lt;code&gt;parallel&lt;/code&gt; author Ole Tange explains, the original version was leveraging &lt;code&gt;make&lt;/code&gt; because it allows asynchronous processes as well.&lt;/p&gt;

</description>
      <category>shell</category>
      <category>automation</category>
      <category>concurrency</category>
      <category>performance</category>
    </item>
    <item>
      <title>Ports for ssh, scp, rsync</title>
      <dc:creator>Florian Stolzenhain</dc:creator>
      <pubDate>Tue, 20 Feb 2024 13:48:02 +0000</pubDate>
      <link>https://dev.to/stolzenhain/ports-for-ssh-scp-rsync-2f3i</link>
      <guid>https://dev.to/stolzenhain/ports-for-ssh-scp-rsync-2f3i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://studioagenturbuero.com/archive/2022/ssh-port-args/"&gt;Original post&lt;/a&gt; on my blog, happy to include feedback!&lt;br&gt;
Cover: &lt;a href="https://www.britishmuseum.org/collection/object/P_1949-0411-4999-1-26"&gt;Théophile Steinlen&lt;/a&gt;, via &lt;a href="https://clawmarks.tumblr.com/post/735451976573255680/des-chats-th%C3%A9ophile-alexandre-steinlen-1898"&gt;Clawmarks&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Have to look&lt;sup id="fnref1"&gt;1&lt;/sup&gt; this&lt;sup id="fnref2"&gt;2&lt;/sup&gt; up&lt;sup id="fnref3"&gt;3&lt;/sup&gt; every time&lt;sup id="fnref4"&gt;4&lt;/sup&gt;:&lt;/p&gt;

&lt;p&gt;Assuming you're connected to a machine like&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh user@my.host.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and want to transfer files afterwards, you'll likely update your recent command to&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scp user@my.host.server:/my/folder/my.file dest/folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rsync -a user@my.host.server:/my/folder dest/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;for copying said files. So far, so good.&lt;/p&gt;

&lt;p&gt;When relying on ports, this gets way more complicated due to differing parameter styles for each command which are&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# `-p[port]`&lt;/span&gt;
ssh &lt;span class="nt"&gt;-p222&lt;/span&gt; user@my.host.server

&lt;span class="c"&gt;# `-P [port]`&lt;/span&gt;
scp &lt;span class="nt"&gt;-P&lt;/span&gt; 222 user@my.host.server:/my/folder/my.file dest/folder

&lt;span class="c"&gt;# set port on custom remote shell&lt;/span&gt;
rsync &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"ssh -p222"&lt;/span&gt; user@my.host.server:/my/folder/my.file dest/folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Note that rsync has more options for defining TCP daemon ports with &lt;code&gt;--port=[PORT]&lt;/code&gt; which is probably not what you want)&lt;/p&gt;

&lt;p&gt;You're welcome!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://man.openbsd.org/ssh"&gt;ssh manpage&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://man.openbsd.org/scp"&gt;scp manpage&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://download.samba.org/pub/rsync/rsync.1"&gt;rsync manpage&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Find &lt;a href="https://unix.stackexchange.com/questions/195179/is-there-a-linux-graphics-program-that-displays-man-commands-in-a-browser"&gt;offline documentation tools&lt;/a&gt; on Stackoverflow … or use &lt;a href="https://blog.kapeli.com/linux-man-pages-in-dash"&gt;Dash&lt;/a&gt; on Macs and &lt;a href="https://zealdocs.org/"&gt;Zeal&lt;/a&gt; &lt;a href="https://github.com/zealdocs/zeal/issues/115#issuecomment-308795433"&gt;man docsets&lt;/a&gt; on Windows ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ssh</category>
      <category>scp</category>
      <category>rsync</category>
      <category>ports</category>
    </item>
    <item>
      <title>Automate Wordpress setups via WP-CLI</title>
      <dc:creator>Florian Stolzenhain</dc:creator>
      <pubDate>Fri, 03 Nov 2023 15:56:57 +0000</pubDate>
      <link>https://dev.to/stolzenhain/automate-wordpress-setups-via-wp-cli-37mf</link>
      <guid>https://dev.to/stolzenhain/automate-wordpress-setups-via-wp-cli-37mf</guid>
      <description>&lt;p&gt;&lt;a href="https://studioagenturbuero.com/archive/2021/wp-cli-cheatsheet/"&gt;Original post&lt;/a&gt; on my blog, happy to include feedback!&lt;br&gt;
Cover: &lt;a href="https://www.flickr.com/photos/usnationalarchives/7158238104/"&gt;U.S. National Archives&lt;/a&gt;, via &lt;a href="https://nos.twnsnd.co/post/75491786304/train-depot-in-somewhere-kansas"&gt;New Old Stock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;These examples assume a working local WP-CLI helper –&lt;br&gt;
for installing and file structure advice, see 4) installing WP-CLI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup vanilla Wordpress from scratch&lt;/li&gt;
&lt;li&gt;Migrate an existing instance&lt;/li&gt;
&lt;li&gt;
Update an instance

&lt;ol&gt;
&lt;li&gt;Specify version and locale&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;See also&lt;/li&gt;
&lt;li&gt;Further reading&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1) Setup vanilla Wordpress from scratch
&lt;/h2&gt;

&lt;p&gt;Assumes an existing local database and host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# root dir is project dir&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; wordpress
&lt;span class="nb"&gt;cd &lt;/span&gt;wordpress

&lt;span class="c"&gt;# download to current folder, see&lt;/span&gt;
&lt;span class="c"&gt;# https://developer.wordpress.org/cli/commands/core/download/&lt;/span&gt;
wp core download &lt;span class="nt"&gt;--locale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_GB

&lt;span class="c"&gt;# TODO: using the password on the shell is not ideal, see&lt;/span&gt;
&lt;span class="c"&gt;# https://developer.wordpress.org/cli/commands/config/create/#examples&lt;/span&gt;
wp config create &lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;name] &lt;span class="nt"&gt;--dbuser&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;user] &lt;span class="nt"&gt;--dbpass&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;pass]

&lt;span class="c"&gt;# this will return a user password&lt;/span&gt;
wp core &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;website.local &lt;span class="nt"&gt;--title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Website title"&lt;/span&gt; &lt;span class="nt"&gt;--admin_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"janitor"&lt;/span&gt; &lt;span class="nt"&gt;--admin_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"foo@bar.local"&lt;/span&gt;

&lt;span class="c"&gt;# create local wp-cli config for htaccess generation, see&lt;/span&gt;
&lt;span class="c"&gt;# https://developer.wordpress.org/cli/commands/rewrite/structure/&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"apache_modules:&lt;/span&gt;&lt;span class="se"&gt;\n\&lt;/span&gt;&lt;span class="s2"&gt;
  - mod_rewrite&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ../wp-cli.local.yml

&lt;span class="c"&gt;# create htaccess&lt;/span&gt;
wp rewrite structure &lt;span class="s1"&gt;'/%year%/%monthnum%/%postname%/'&lt;/span&gt; &lt;span class="nt"&gt;--hard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;TODO:&lt;/strong&gt; add SQLite example&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Migrate an existing instance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp db reset &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;span class="nb"&gt;gunzip&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;file.sql.gz] &lt;span class="nt"&gt;--stdout&lt;/span&gt; | wp db import -

&lt;span class="c"&gt;# reset pw of user `admin` to `test`&lt;/span&gt;
wp &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"wp_set_password( 'test', get_user_by( 'login', 'admin' )-&amp;gt;ID );"&lt;/span&gt;

&lt;span class="c"&gt;# set local url&lt;/span&gt;
&lt;span class="c"&gt;# needs http[s]:// protocol and quotes&lt;/span&gt;
wp option update siteurl &lt;span class="s1"&gt;'http://domain.local'&lt;/span&gt;
wp option update home &lt;span class="s1"&gt;'http://domain.local'&lt;/span&gt;

&lt;span class="c"&gt;# flush redirects&lt;/span&gt;
wp rewrite flush
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3) Update an instance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# update core&lt;/span&gt;
wp core update
&lt;span class="c"&gt;# update all themes&lt;/span&gt;
wp theme update &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;span class="c"&gt;# update all plugins&lt;/span&gt;
wp plugin update &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;span class="c"&gt;# update language&lt;/span&gt;
wp language core update
wp language plugin &lt;span class="nt"&gt;--all&lt;/span&gt; update
wp language theme &lt;span class="nt"&gt;--all&lt;/span&gt; update
&lt;span class="c"&gt;# update db scheme&lt;/span&gt;
&lt;span class="c"&gt;# otherwise, an admin user will be prompted&lt;/span&gt;
wp core update-db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; paradoxically, a working &lt;code&gt;wp-config.php&lt;/code&gt; is mandatory for WP-CLI to work. You can use the helper command &lt;code&gt;wp config create&lt;/code&gt; if you don't want to clone &lt;code&gt;wp-config-sample.php&lt;/code&gt; manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specify version and locale
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp core update &lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5.4 &lt;span class="nt"&gt;--locale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check locale availability via &lt;a href="https://translate.wordpress.org/"&gt;WP translation platform&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4) See also
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Globally installing WP-CLI vs keeping a local version
&lt;/h3&gt;

&lt;p&gt;You can&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://wp-cli.org/#installing"&gt;move &lt;code&gt;wp-cli.phar&lt;/code&gt; to a global &lt;code&gt;wp&lt;/code&gt; binary&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;keep a local install in you're projects root folder e.g. at &lt;code&gt;/bin/wp-cli.phar&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;which makes sure each script continues to work on a remote installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloading core programmatically without WP-CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# grab and unpack the latest locale-specific release&lt;/span&gt;
curl https://de.wordpress.org/latest-en_GB.tar.gz &lt;span class="nt"&gt;-o&lt;/span&gt; latest-en_GB.tar.gz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvzf&lt;/span&gt; latest-en_GB.tar.gz
&lt;span class="nb"&gt;cd &lt;/span&gt;wordpress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5) Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;alternative to downloading core: the &lt;a href="https://github.com/markjaquith/WordPress-Skeleton"&gt;Wordpress Skeleton&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;applying &lt;code&gt;--allow-root&lt;/code&gt;: &lt;a href="https://stackoverflow.com/questions/39670418/setting-wordpress-siteurl-using-wp-cli-with-wamp-virtual-host"&gt;php - Setting WordPress siteurl using wp-cli with WAMP virtual host - Stack Overflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://onextrapixel.com/13-useful-wordpress-sql-queries-you-wish-you-knew-earlier/"&gt;13 Useful WordPress SQL Queries You Wish You Knew Earlier&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>automation</category>
      <category>shell</category>
      <category>cheatsheet</category>
    </item>
  </channel>
</rss>
