<?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: Wouter Van Rossem</title>
    <description>The latest articles on DEV Community by Wouter Van Rossem (@wvrossem).</description>
    <link>https://dev.to/wvrossem</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%2F2661557%2F9efe2d67-b22d-4064-acb1-8b151062214f.jpg</url>
      <title>DEV Community: Wouter Van Rossem</title>
      <link>https://dev.to/wvrossem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wvrossem"/>
    <language>en</language>
    <item>
      <title>Fixing Linux Backup Sync Issues for exFAT Compatibility</title>
      <dc:creator>Wouter Van Rossem</dc:creator>
      <pubDate>Sat, 11 Jan 2025 04:24:09 +0000</pubDate>
      <link>https://dev.to/wvrossem/fixing-linux-backup-sync-issues-for-exfat-compatibility-267p</link>
      <guid>https://dev.to/wvrossem/fixing-linux-backup-sync-issues-for-exfat-compatibility-267p</guid>
      <description>&lt;p&gt;A recent issue with synchronizing my home directory to my exFAT-formatted external SSD surfaced while using KDE’s Kup Backup application. Errors occurred because some filenames contained characters not supported by the exFAT file system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding exFAT's Filename Restrictions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many external drives use exFAT for cross-platform compatibility. However, exFAT prohibits certain characters in filenames, which can cause issues when backing up files from Linux filesystems.&lt;/p&gt;

&lt;p&gt;Filenames &lt;a href="https://en.wikipedia.org/wiki/ExFAT" rel="noopener noreferrer"&gt;can include all Unicode characters except&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"&lt;/code&gt; (double quote)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; (asterisk)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:&lt;/code&gt; (colon)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;&lt;/code&gt; (less than)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;gt;&lt;/code&gt; (greater than)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;?&lt;/code&gt; (question mark)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\&lt;/code&gt; (backslash)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; (forward slash)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt; (pipe)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Filenames also cannot end with a space or a period, but these cases are not currently handled by the script below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identifying Problematic Files&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kup Backup logs errors related to such files in &lt;code&gt;~/.cache/kup/kup_plan1.log&lt;/code&gt;. Reviewing this log allowed me to isolate the problematic files. If only a few files are affected, the simple solution is to manually rename them, removing or replacing any unsupported characters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automating the Renaming Process with a Bash Script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a large number of files, the renaming process can be automated. The following Bash script (corrected from an initial version created with ChatGPT) identifies and renames files in given directories that contain invalid characters, replacing each with an underscore.&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;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Directories to scan&lt;/span&gt;
&lt;span class="nv"&gt;directories&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
    &lt;span class="s2"&gt;"/path/to/your/directory1"&lt;/span&gt;
    &lt;span class="s2"&gt;"/path/to/your/directory2"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Array of characters to replace&lt;/span&gt;
&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nv"&gt;char_map&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'?'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'\\'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'|'&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s1"&gt;'_'&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Function to rename files&lt;/span&gt;
rename_files&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="c"&gt;# Use find to search for files in "$dir" with names containing restricted characters, &lt;/span&gt;
    &lt;span class="c"&gt;# then pass each result to the while loop for processing.&lt;/span&gt;
    find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-depth&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*["*:&amp;lt;&amp;gt;?\\|]*'&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; file&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="c"&gt;# Get the directory and base name of the file&lt;/span&gt;
        &lt;span class="nv"&gt;dir_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;base_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Rename the file&lt;/span&gt;
        &lt;span class="nv"&gt;new_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$base_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;char &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!char_map[@]&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;do
            &lt;/span&gt;&lt;span class="nv"&gt;new_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;new_name&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$char&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;char_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$char&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;done&lt;/span&gt;

        &lt;span class="c"&gt;# If the filename has changed, rename it&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$base_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir_path&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$new_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;fi
    done&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Iterate over directories and rename files&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;dir &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;directories&lt;/span&gt;&lt;span class="p"&gt;[@]&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;do
    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;rename_files &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Directory &lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt; does not exist."&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How the Script Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The script iterates over each specified directory, checks if it exists, and calls the &lt;code&gt;rename_files&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rename_files&lt;/code&gt; function uses &lt;code&gt;find&lt;/code&gt; to locate files with restricted characters in their names. It then iteratively replaces each restricted character with an underscore and renames the file using &lt;code&gt;mv&lt;/code&gt;, with verbose flag to explain what is being done. The &lt;code&gt;-n&lt;/code&gt; flag makes sure it will not overwrite an existing file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage Instructions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ve tested the script, but remember to take precautions to prevent data loss when running it.&lt;/p&gt;

&lt;p&gt;After running the process, verify that the files were renamed correctly. Manual post-processing is needed for files that would have caused duplicate names (these files are skipped).&lt;/p&gt;

&lt;p&gt;If you encounter any issues or have suggestions for improvements, feel free to reach out and let me know.  &lt;/p&gt;

</description>
      <category>linux</category>
      <category>exfat</category>
      <category>bash</category>
      <category>microsoft</category>
    </item>
  </channel>
</rss>
