{"id":11999,"date":"2022-06-19T19:34:39","date_gmt":"2022-06-20T02:34:39","guid":{"rendered":"https:\/\/www.oeconomist.com\/blogs\/daniel\/?p=11999"},"modified":"2022-07-08T15:57:38","modified_gmt":"2022-07-08T22:57:38","slug":"virtual-shelving","status":"publish","type":"post","link":"https:\/\/www.oeconomist.com\/blogs\/daniel\/?p=11999","title":{"rendered":"Virtual Shelving"},"content":{"rendered":"<p style=\"font-style: italic ;\">&#91;This entry was revised and expanded on 2022:07\/07.&#93;<\/p> <p>I am always uncomfortable with the process of organizing books and articles on shelves or in boxes.  I desire to have them grouped by each author and by each subject of interest; these desires cannot be reconciled without having multiple copies of each book and of each article, which multiplicity I cannot afford.<\/p> <p>Electronic copies are a different matter.  Even without multiple copies, <a href=\"?p=11981\">symbolic links, which I discussed in a previous entry<\/a>, make it possible effectively to list the same file in multiple directories.  Here&iuml;n, I'll explain the principle structure that I use for organizing documents, and I'll present some small utilities that facilitate creating and maintaining that structure on <abbr class=\"noshrink\" title=\"Portable Operating System Interface\">POSIX<\/abbr>-compliant file systems.  This structure is not as fine-grained as might be imagined, but it strikes a balance appropriate to my purposes. (For a more sophisticated system one should employ an application storing and retrieving documents mediated by a cataloguing relational database.)<\/p> <p>As with many systems, mine have each a directory named <q><code>Documents<\/code><\/q>.  Its two subdirectories relevant to this discussion are <code>Authors<\/code> and <code>Subjects<\/code>.  <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/documents_376x132.png\" width=\"376\" height=\"132\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0 ; max-width: 100% ; width: 376px ; max-height: 35.2vw ; height: 132px ;\" \/><\/p> <p>The entries in <code>Subjects<\/code> are subdirectories with names such as <q><code>Economics<\/code><\/q>, <q><code>Logic and Probability<\/code><\/q>, <q><code>Mathematics<\/code><\/q>, and <q><code>Philosophy<\/code><\/q>.  <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/subjects_450x308.png\" width=\"450\" height=\"308\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0 ; max-width: 100% ; width: 450px ; max-height: 68.5vw ; height: 308px ;\" \/><\/p> <p>In turn, the entries in each of these are subdirectories with the names of authors. <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/logic_450x397.png\" width=\"450\" height=\"397\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0 ; max-width: 100% ; width: 450px ; max-height: 88.3vw ; height: 397px ;\" \/><\/p> <p>Finally, in each of these subdirectories are entries for files containing their work <em>corresponding to the superdirectory<\/em>.  For example, <code>Documents\/Subjects\/Logic and Probability\/Johnson William Ernest\/<\/code> would have entries for works by him on logic or on probability, <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/subjects_full_151x475.png\" width=\"151\" height=\"475\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0.5em ; max-width: 100% ; width: 151px ; max-height: 314.6vw ; height: 475px ;\" \/> but his article on indifference curves would be listed instead in <code>Documents\/Subjects\/Economics\/Johnson William Ernest\/<\/code>.<\/p> <p>Most of the subdirectories of <code>Authors<\/code> have <em>names<\/em> corresponding to the subdirectories in the third level of the <code>Subjects<\/code> substructure, but all of these subdirectories in <code>Authors<\/code> are different directories from those in the <code>Subjects<\/code> substructure. <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/authors_450x308.png\" width=\"450\" height=\"308\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0 ; max-width: 100% ; width: 450px ; max-height: 68.5vw ; height: 308px ;\" \/><\/p> <p>Each of most of these subdirectories of <code>Authors<\/code> lists not subdirectories nor files, but <em>symbolic links<\/em>. <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/johnson_450x397.png\" width=\"450\" height=\"397\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0.5em ; max-width: 100% ; width: 450px ; max-height: 88.3vw ; height: 397px ;\" \/> These links take their names from the subdirectories of <code>Subjects<\/code>, but they do not link to those subdirectories.  Instead, each links to an author-specific sub-subdirectory.  Thus, for example, <code>Documents\/Authors\/Johnson William Ernest\/Logic and Probability<\/code> is a symbolic link to <code>Documents\/Subjects\/Logic and Probability\/Johnson William Ernest<\/code>.  It is <em>as if<\/em> the subject-specific collection of an author's works is the author-specific collection of works on that subject, <em>just as it should be<\/em>. <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/06\/path_example_377x476.png\" width=\"377\" height=\"476\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0 ; max-width: 100% ; width: 377px ; max-height: 126.3vw ; height: 476px ;\" \/><\/p> <p>One could, instead, use the complementary organization, in which the <code>Subjects<\/code> substructure were ultimately dependent upon the <code>Authors<\/code> substructure, or use a hybrid organization in which some of the dependency flows one way and some the other.  The determinant should be what is most important to preserve if the collection is copied to a file system that does not support symbolic links, as in the case of a <abbr class=\"noshrink\" title=\"Secure Digital\">SD<\/abbr> card with a <abbr class=\"noshrink\" title=\"File Allocation Table\">FAT<\/abbr> file system.<\/p> <p>I've sketched the principal structure, but want to note useful complications of two sorts.<\/p> <p>The first is that symbolic links may be used to place some subjects effectively under others.  For example, logic an probability fall within the scope of philosophy.  As well as having a directory named <q><code>Logic and Probability<\/code><\/q> listed in <code>Subjects<\/code>, I have a symbolic link to it listed in <code>Philosophy<\/code>. <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/07\/sub-subjects_413x308.png\" width=\"413\" height=\"308\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0.5em ; max-width: 100% ; width: 413px ; max-height: 75.6vw ; height: 308px ;\" \/> Indeed, when a subject falls within the intersection of other subjects, each may have such a symbolic link, and I have links to <code>Documents\/Subjects\/Logic and Probability<\/code> not only in <code>Philosophy<\/code> but in <code>Mathematics<\/code> and in <code>Economics<\/code>.<\/p> <p>The second is that symbolic links may be used effectively to list a document with multiple authors in the directory for each author. <img loading=\"lazy\" decoding=\"async\" src=\"wp-content\/uploads\/2022\/07\/coauth_376x486.png\" width=\"376\" height=\"486\" alt=\"\" style=\"display: block ; margin-top: 0.5em ; margin-left: auto ; margin-right: auto ; margin-bottom: 0.5em ; max-width: 100% ; width: 376px ; max-height: 129.3vw ; height: 486px ;\" \/> And essentially the same device may be used to classify a single document under different subjects.<\/p> <p>Although this organization is not especially fine-grained, it requires the creation of <em>many<\/em> directories and symbolic links.  I've written seven utilities in <a href=\"https:\/\/python.org\/\">Python<\/a> to reduce the burden.  Two of those utilities were presented in <a href=\"?p=11981\">a previous &#39;blog entry<\/a> because they can be put to more general purpose.  Here, I will present five more.<\/p> <p>(Again, these utilities are written for <abbr class=\"noshrink\" title=\"Portable Operating System Interface\">POSIX<\/abbr>-compliant file systems.  <em>Windows is not <abbr class=\"noshrink\" title=\"Portable Operating System Interface\">POSIX<\/abbr>-compliant.<\/em>  A full discussion of the relevant issues would be tedious, as would be an effort to rewrite these programs to support Windows.)<\/p> <p><strong><!--more &#91;Read more.&#93;--><\/strong>The first of these programs, <code>mkdocdir.py<\/code>, takes two or three arguments, and creates corresponding directories and symbolic links.  The first argument is the name of an author, and the second is the name of a subject.  A command <span style=\"display: block ; margin-top: 0.5em ; margin-left: 1em ; margin-right: auto; margin-bottom: 0.5em ; text-align: center ;\"><code>mkdocdir.py \"De Morgan Augustus\" Mathematics<\/code><\/span> will create directories <code>Documents<\/code>, <code>Documents\/Authors<\/code>, <code>Documents\/Subjects<\/code>, <code>Documents\/Authors\/De Morgan Augustus<\/code>, <code>Documents\/Subjects\/Mathematics<\/code>, and <code>Documents\/Subjects\/Mathematics\/De Morgan<\/code> unless they already exist, and will create the symbolic link <code>Documents\/Authors\/De Morgan Augustus\/Mathematics<\/code> (to <code>Documents\/Subjects\/Mathematics\/De Morgan<\/code>) unless it already exists.  The optional third argument, uses an alternative to <code>Documents<\/code>, but is otherwise the same; a command <span style=\"display: block ; margin-top: 0.5em ; margin-left: 1em ; margin-right: auto; margin-bottom: 0.5em ; text-align: center ;\"><code>mkdocdir.py \"De Morgan Augustus\" Mathematics MyDocs<\/code><\/span> will create <code>MyDocs\/Subjects\/Mathematics\/De Morgan Augustus<\/code> &amp;c.<\/p> <div style=\"margin-top: 0 ; margin-left: 1em ; margin-right: 0 ; margin-bottom: 0 ; overflow: auto ;\"><pre>#!\/usr\/bin\/env python\r\nimport os\r\nimport sys\r\n\r\nsubjectSource = True\r\n\r\nargc = len(sys.argv)\r\nif argc < 3 or argc > 4:\r\n    prog_name = sys.argv[0][sys.argv[0].rindex(\"\/\")+1:]\r\n    print(\"Syntax: \" + prog_name\r\n                     + \" &lt;author-name&gt; &lt;subject&gt; [&lt;documents-directory&gt;]\\n\"\r\n                     +\r\n          \"&lt;documents-directory&gt; defaults to \\\"Documents\\\".\\n\"\r\n                     +\r\n          \"Examples: \" + prog_name\r\n                       + \" \\\"De Morgan Augustus\\\" Mathematics\\n\"\r\n                     +\r\n          \"          \" + prog_name\r\n                       + \" Menger_Carl Economics MyDocs\")\r\nelse:\r\n    if argc < 4:\r\n        dir_documents = os.path.expanduser(\"~\") + \"\/Documents\"\r\n    else:\r\n        dir_documents = sys.argv[3]\r\n    os.makedirs(dir_documents,0o777,True)\r\n    os.chdir(dir_documents)\r\n    if subjectSource == True:\r\n        dir_sources = \"Subjects\"\r\n        dir_links = \"Authors\"\r\n        d3 = sys.argv[1]\r\n        d4 = sys.argv[2]\r\n    else:\r\n        dir_sources = \"Authors\"\r\n        dir_links = \"Subjects\"\r\n        d3 = sys.argv[2]\r\n        d4 = sys.argv[1]\r\n    source = dir_sources + \"\/\" + d4 + \"\/\" + d3\r\n    link = dir_links + \"\/\" + d3 + \"\/\" + d4\r\n    os.makedirs(source,0o777,True)\r\n    os.makedirs(dir_links + \"\/\" + d3,0o777,True)\r\n    if not os.path.exists(link):\r\n        os.chdir(dir_links + \"\/\" + d3)\r\n        os.symlink(\"..\/..\/\" + dir_sources + \"\/\" + d4 + \"\/\" + d3,d4)<\/pre><\/div> <p>The second, <code>cpdoc.py<\/code>, copies a file into the structure, creating directories and symbolic links as necessary; it thus combines the functionality of creating the relevant directories and symbolic link with that of copying a file into the structure.  <code>cpdoc.py<\/code> takes three or four arguments.  The first is a file-path, the second the name of an author, and the third the name of a subject.  The optional fourth again specifies an alternative to <code>Documents<\/code>.  A command <span style=\"display: block ; margin-top: 0.5em ; margin-left: 1em ; margin-right: auto; margin-bottom: 0.5em ; text-align: center ;\"><code>cpdoc.py \"A Treatise on Probability.pdf\" \"Keynes John Maynard\" \"Logic and Probability\"<\/code><\/span> will create the relevant directories and symbolic link, and then copy a file named <q><code>A Treatise on Probability.pdf<\/code><\/q> from the present working directory into <code>Documents\/Subjects\/Logic and Probability\/Keynes John Maynard<\/code>.<\/p> <div style=\"margin-top: 0 ; margin-left: 1em ; margin-right: 0 ; margin-bottom: 0 ; overflow: auto ;\"><pre>#!\/usr\/bin\/env python\r\nimport os\r\nimport sys\r\nimport shutil\r\n\r\nsubjectSource = True\r\n\r\nargc = len(sys.argv)\r\nif argc < 4 or argc > 5:\r\n    prog_name = sys.argv[0][sys.argv[0].rindex(\"\/\")+1:]\r\n    print(\"Syntax: \" + prog_name\r\n                     +\r\n          \" &lt;file&gt; &lt;author-name&gt; &lt;subject&gt; [&lt;documents-directory&gt;]\\n\"\r\n                     +\r\n          \"&lt;documents-directory&gt; defaults to \\\"Documents\\\".\\n\"\r\n                     +\r\n          \"Examples: \" + prog_name\r\n                       +\r\n          \" ~\/Downloads\/On_the_Syllogism.pdf \\\"De Morgan Augustus\\\" \\\"Logic\\\"\\n\"\r\n                     +\r\n          \"          \" + prog_name\r\n                       +\r\n          \" introductorylec02whatgoog.pdf Whately_Richard Economics MyDocs\")\r\nelse:\r\n    if argc < 5:\r\n        dir_documents = os.path.expanduser(\"~\") + \"\/Documents\"\r\n    else:\r\n        dir_documents = sys.argv[4]\r\n    os.makedirs(dir_documents,0o777,True)\r\n    file = os.path.abspath(sys.argv[1])\r\n    os.chdir(dir_documents)\r\n    if subjectSource == True:\r\n        dir_sources = \"Subjects\"\r\n        dir_links = \"Authors\"\r\n        d3 = sys.argv[2]\r\n        d4 = sys.argv[3]\r\n    else:\r\n        dir_sources = \"Authors\"\r\n        dir_links = \"Subjects\"\r\n        d3 = sys.argv[3]\r\n        d4 = sys.argv[2]\r\n    source = dir_sources + \"\/\" + d4 + \"\/\" + d3\r\n    link = dir_links + \"\/\" + d3 + \"\/\" + d4\r\n    os.makedirs(source,0o777,True)\r\n    os.makedirs(dir_links + \"\/\" + d3,0o777,True)\r\n    if not os.path.exists(link):\r\n        os.chdir(dir_links + \"\/\" + d3)\r\n        os.symlink(\"..\/..\/\" + dir_sources + \"\/\" + d4 + \"\/\" + d3,d4)\r\n     shutil.copy2(file,dir_documents + \"\/\" + source)<\/pre><\/div> <p>The third, <code>mvdoc.py<\/code>, is the same as <code>cpdoc.py<\/code>, except that <code>mvdoc.py<\/code> <em>moves<\/em> the file specified into the structure, instead of copying it.<\/p> <div style=\"margin-top: 0 ; margin-left: 1em ; margin-right: 0 ; margin-bottom: 0 ; overflow: auto ;\"><pre>#!\/usr\/bin\/env python\r\nimport os\r\nimport sys\r\nimport shutil\r\n\r\nsubjectSource = True\r\n\r\nargc = len(sys.argv)\r\nif argc < 4 or argc > 5:\r\n    prog_name = sys.argv[0][sys.argv[0].rindex(\"\/\")+1:]\r\n    print(\"Syntax: \" + prog_name\r\n                     +\r\n          \" &lt;file&gt; &lt;author-name&gt; &lt;subject&gt; [&lt;documents-directory&gt;]\\n\"\r\n                     +\r\n          \"&lt;documents-directory&gt; defaults to \\\"Documents\\\".\\n\"\r\n                     +\r\n          \"Examples: \" + prog_name\r\n                       +\r\n          \" ~\/Downloads\/On_the_Syllogism.pdf \\\"De Morgan Augustus\\\" \\\"Logic\\\"\\n\"\r\n                     +\r\n          \"          \" + prog_name\r\n                       +\r\n          \" introductorylec02whatgoog.pdf Whately_Richard Economics MyDocs\")\r\nelse:\r\n    if argc < 5:\r\n        dir_documents = os.path.expanduser(\"~\") + \"\/Documents\"\r\n    else:\r\n        dir_documents = sys.argv[4]\r\n    os.makedirs(dir_documents,0o777,True)\r\n    file = os.path.abspath(sys.argv[1])\r\n    os.chdir(dir_documents)\r\n    if subjectSource == True:\r\n        dir_sources = \"Subjects\"\r\n        dir_links = \"Authors\"\r\n        d3 = sys.argv[2]\r\n        d4 = sys.argv[3]\r\n    else:\r\n        dir_sources = \"Authors\"\r\n        dir_links = \"Subjects\"\r\n        d3 = sys.argv[3]\r\n        d4 = sys.argv[2]\r\n    source = dir_sources + \"\/\" + d4 + \"\/\" + d3\r\n    link = dir_links + \"\/\" + d3 + \"\/\" + d4\r\n    os.makedirs(source,0o777,True)\r\n    os.makedirs(dir_links + \"\/\" + d3,0o777,True)\r\n    if not os.path.exists(link):\r\n        os.chdir(dir_links + \"\/\" + d3)\r\n        os.symlink(\"..\/..\/\" + dir_sources + \"\/\" + d4 + \"\/\" + d3,d4)\r\n     shutil.move(file,dir_documents + \"\/\" + source)<\/pre><\/div> <p>The fourth places a symbolic links to a specific work in another directory.  It can be used effectively to list a single work under multiple directories, associated with different authors or with different subjects or with both.  <code>lndoc.py<\/code> takes three or four arguments.  The first is a file-path, the second the name of an author, and the third the name of a subject.  The optional fourth again specifies an alternative to <code>Documents<\/code>.  A command <span style=\"display: block ; margin-top: 0.5em ; margin-left: 1em ; margin-right: auto; margin-bottom: 0.5em ; text-align: center ;\"><code>lndoc.py \"Reconsideration of the Theory of Value.pdf\" \"Allen Roy George Douglas\" Economics<\/code><\/span> will create the relevant directories and symbolic link to a directory, and then create a symbolic link to a file named <q><code>Reconsideration of the Theory of Value.pdf<\/code><\/q> from the present working directory into <code>Documents\/Subjects\/Economic\/Allen Roy George Douglas<\/code>.  It will also create the associated directories and a symbolic link <code>Documents\/Authors\/Allen Roy George Douglas\/Economics<\/code> to <code>Documents\/Subjects\/Economics\/Allen Roy George Douglas<\/code> if these do not already exist.<\/p> <div style=\"margin-top: 0 ; margin-left: 1em ; margin-right: 0 ; margin-bottom: 0 ; overflow: auto ;\"><pre>#!\/usr\/bin\/env python\r\nimport os\r\nimport sys\r\nimport shutil\r\n\r\nsubjectSource = True\r\n\r\nargc = len(sys.argv)\r\nif argc < 4 or argc > 5:\r\n    prog_name = sys.argv[0][sys.argv[0].rindex(\"\/\")+1:]\r\n    print(\"Syntax: \" + prog_name\r\n                     +\r\n          \" &lt;file&gt; &lt;author-name&gt; &lt;subject&gt; [&lt;documents-directory&gt;]\\n\"\r\n                     +\r\n          \"<documents-directory> defaults to \\\"Documents\\\".\\n\"\r\n                     +\r\n          \"Examples: \" + prog_name\r\n                       +\r\n          \" ~\/Downloads\/On_the_Syllogism.pdf \\\"De Morgan Augustus\\\" \\\"Logic\\\"\\n\"\r\n                     +\r\n          \"          \" + prog_name\r\n                       +\r\n          \" introductorylec02whatgoog.pdf Whately_Richard Economics MyDocs\")\r\nelse:\r\n    if argc < 5:\r\n        dir_documents = os.path.expanduser(\"~\") + \"\/Documents\"\r\n    else:\r\n        dir_documents = sys.argv[4]\r\n    os.makedirs(dir_documents,0o777,True)\r\n    file = os.path.abspath(sys.argv[1])\r\n    os.chdir(dir_documents)\r\n    if subjectSource == True:\r\n        dir_sources = \"Subjects\"\r\n        dir_links = \"Authors\"\r\n        d3 = sys.argv[2]\r\n        d4 = sys.argv[3]\r\n    else:\r\n        dir_sources = \"Authors\"\r\n        dir_links = \"Subjects\"\r\n        d3 = sys.argv[3]\r\n        d4 = sys.argv[2]\r\n    source = dir_sources + \"\/\" + d4 + \"\/\" + d3\r\n    link = dir_links + \"\/\" + d3 + \"\/\" + d4\r\n    os.makedirs(source,0o777,True)\r\n    os.makedirs(dir_links + \"\/\" + d3,0o777,True)\r\n    if not os.path.exists(link):\r\n        os.chdir(dir_links + \"\/\" + d3)\r\n        os.symlink(\"..\/..\/\" + dir_sources + \"\/\" + d4 + \"\/\" + d3,d4)\r\n    os.symlink(file,dir_documents + \"\/\" + source + \"\/\" + os.path.basename(file))\r\n<\/documents-directory><\/pre><\/div> <p>Each of the above four programs contains a line <q><code>subjectSource = True<\/code><\/q>.  If this line is changed to <q><code>subjectSource = False<\/code><\/q> then the aforemention complementary structure is created, with the <code>Subjects<\/code> substructure dependent upon the <code>Authors<\/code> substructure.  The code could be modified so that a command-line switch determined which organization were used.<\/p> <p>The program <code>mkdoclnk.py<\/code> is used to create the dependent substructure from the independent substructure.  That is to say that if the documents are stored in the <code>Subjects<\/code> substructure and the <code>Authors<\/code> substructure has not been created or not fully created, then <code>mkdoclnk.py<\/code>.  If the documents are stored in the <code>Authors<\/code> substructure, then <code>mkdoclnk.py<\/code> can create a dependent <code>Subjects<\/code> substructure.  If the substructures have different names (such as <q><code>Autori<\/code><\/q> and <q><code>Materia<\/code><\/q>), then <code>mkdoclnk.py<\/code> can accept those.  If a hybrid system is to be used, two passes of <code>mkdoclnk.py<\/code> can complete it.<\/p>  <code>mkdoclnk.py<\/code> takes zero to three arguments.  If the first is not given, then the source substructure is assumed to be in a directory named <q><code>Subjects<\/code><\/q>.  If the second is not given, then the dependent substructure is assumed to be in a directory named <q><code>Authors<\/code><\/q>.  And if the third argument is not given, them the source and dependent substructures are assumed to be in a directory named <q><code>Documents<\/code><\/q>.  A command <span style=\"display: block ; margin-top: 0.5em ; margin-left: 1em ; margin-right: auto; margin-bottom: 0.5em ; text-align: center ;\"><code>mkdoclnk.py<\/code><\/span> constructs the <code>Authors<\/code> substructure in <code>Documents<\/code> from the <code>Subjects<\/code> substructure in <code>Documents<\/code>.  A command <span style=\"display: block ; margin-top: 0.5em ; margin-left: 1em ; margin-right: auto; margin-bottom: 0.5em ; text-align: center ;\"><code>mkdoclnk.py Pundits Topics Yappings<\/code><\/span> constructs a <code>Topics<\/code> substructure in <code>Yappings<\/code> from a <code>Pundits<\/code> substructure in <code>Yappings<\/code>. <div style=\"margin-top: 0 ; margin-left: 1em ; margin-right: 0 ; margin-bottom: 0 ; overflow: auto ;\"><pre>#!\/usr\/bin\/env python\r\nimport os\r\nimport sys\r\n\r\nsys.argc = len(sys.argv)\r\nif sys.argc > 4:\r\n    prog_name = sys.argv[0][sys.argv[0].rindex(\"\/\")+1:]\r\n    print(\"Syntax:\\n \" + prog_name\r\n                     + \" [&lt;sources-directory&gt; [&lt;links-directory&gt; [&lt;parent-directory&gt;]]]\\n\"\r\n                     +\r\n          \"Defaults: \" + prog_name + \" Subjects Authors ~\/Documents\\n\"\r\n                     +\r\n          \"Example: \" + prog_name + \" Authors Subjects\")\r\nelse:\r\n    if sys.argc < 4:\r\n        os.chdir(os.path.expanduser(\"~\") + \"\/Documents\")\r\n    else:\r\n        os.chdir(sys.argv[3])\r\n    dir_home = os.getcwd()\r\n    if sys.argc < 3:\r\n        dir_links = \"Authors\"\r\n    else:\r\n        dir_links = sys.argv[2]\r\n    if sys.argc < 2:\r\n        dir_source = \"Subjects\"\r\n    else:\r\n        dir_source = sys.argv[1]\r\n    list_dir_source = [entry for entry in os.scandir(\".\/\" + dir_source)\r\n                 if entry.is_dir() and not os.path.islink(entry)]\r\n    for entry in list_dir_source:\r\n        list_dir_links = [sub_entry for sub_entry in os.scandir(entry.path)\r\n                     if sub_entry.is_dir() and not os.path.islink(sub_entry)]\r\n        for sub_entry in list_dir_links:\r\n            dir_candidate = \".\/\" + dir_links + \"\/\" + sub_entry.name\r\n            if not os.path.exists(dir_candidate):\r\n                os.makedirs(dir_candidate,0o777,True)\r\n            if not os.path.exists(dir_candidate + \"\/\" + entry.name):\r\n                os.chdir(dir_candidate)\r\n                os.symlink(\"..\/..\/\" + dir_source\r\n                           + \"\/\" + entry.name + \"\/\" + sub_entry.name,\r\n                           entry.name)\r\n                os.chdir(dir_home)<\/pre><\/div>","protected":false},"excerpt":{"rendered":"&#91;This entry was revised and expanded on 2022:07\/07.&#93; I am always uncomfortable with the process of organizing books and articles on shelves or in boxes. I desire to have them grouped by each author and by each subject of interest; these desires cannot be reconciled without having multiple copies of each book and of each [&hellip;]","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"categories":[69,4],"tags":[1639,1638,1642,1643,1641,1640,250,1637,1635,1636],"class_list":["post-11999","post","type-post","status-publish","format-standard","hentry","category-information-technology","category-public","tag-document-management","tag-documents","tag-e-books","tag-ebooks","tag-electronic-books","tag-electronic-documents","tag-programming","tag-python","tag-symbolic-links","tag-symlinks"],"_links":{"self":[{"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=\/wp\/v2\/posts\/11999","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=11999"}],"version-history":[{"count":22,"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=\/wp\/v2\/posts\/11999\/revisions"}],"predecessor-version":[{"id":12037,"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=\/wp\/v2\/posts\/11999\/revisions\/12037"}],"wp:attachment":[{"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=11999"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=11999"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.oeconomist.com\/blogs\/daniel\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=11999"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}