title: how to read, change, and write macOS file alias from python
body: <p>Is there any way to read a macOS file alias, modify its contents (particularly the target file path), and write the modified alias back out?</p>
  
  <p>For example, if I have the following directory structure:</p>
  
  <pre><code>./one/file.txt
  ./two/file.txt
  ./file_alias
  </code></pre>
  
  <p>where <code>file_alias</code> resolves to <code>./one/file.txt</code>.  I would like to be able to programmatically, in Python, read <code>./file_alias</code>, determine its path, change 'one' to 'two', and write the revised alias out, overwriting <code>./file_alias</code>.  Upon completion, <code>file_alias</code> would resolve to <code>./two/file.txt</code>.</p>
  
  <p>Searching I've found an answer to a related question that suggests it can't be done (@Milliway's answer to [1]), a Carbon module with no substantive documentation and a statement that its functionality has been removed [2], a partially deprecated macostools module that depends on Carbon [3], an equivalent, unanswered question (except a tentative suggestion to use PyObjC) [4], and a recently updated mac_alias package [5], but have not found a way to accomplish the task based on any of these.</p>
  
  <p>The mac_alias package at first seemed interesting, but I have found no way to import the bytes needed to construct an in-memory <code>Alias</code> object from an existing alias file (using bytes from a binary read of the alias file produces errors) and even if I could construct an in-memory <code>Alias</code> record and modify it, there is no way to write it out to disk.</p>
  
  <p>The machine where I want this is running 10.12.x (Sierra) and I am using the built-in python 2.7.10. I find I can actually import Carbon and macostools, and suspect Carbon.File might conceivably provide what I need, but I cannot find any documentation for it. I could upgrade to High Sierra and/or install and use Python 3.x, but those don't seem to be helpful or relevant at this stage.</p>
  
  <p>I realize that the alias also contains an inode, that will be stale after such a change, but thankfully, in part due to a bug I filed and a bit of persistence back when I was with Apple, an alias resolves the path first, only falls back to the inode if the path fails to resolve, and updates the inode if the path does resolve (and the inode has changed).</p>
  
  <p>Any help, suggestions, pointers appreciated.</p>
  
  <p>[1] <a href="https://stackoverflow.com/questions/22262791/how-to-handle-osx-aliases-in-python-with-os-walk">How to handle OSX Aliases in Python with os.walk()?</a><br>
  [2] <a href="https://docs.python.org/2/library/carbon.html" rel="nofollow noreferrer">https://docs.python.org/2/library/carbon.html</a><br>
  [3] <a href="https://docs.python.org/2/library/macostools.html" rel="nofollow noreferrer">https://docs.python.org/2/library/macostools.html</a><br>
  [4] <a href="https://stackoverflow.com/questions/8360725/change-an-alias-target-python">change an alias target python</a><br>
  [5] <a href="https://pypi.python.org/pypi/mac_alias" rel="nofollow noreferrer">https://pypi.python.org/pypi/mac_alias</a></p>