{"id":29195771,"url":"https://github.com/md-command-line/guide_to_building_structured_bash_programs","last_synced_at":"2026-02-03T09:34:50.433Z","repository":{"id":117098503,"uuid":"136858631","full_name":"md-command-line/guide_to_building_structured_bash_programs","owner":"md-command-line","description":"What you need to know to build scalable bash programs. A few lessons learned.","archived":false,"fork":false,"pushed_at":"2018-06-22T20:44:22.000Z","size":4,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-02T05:05:50.393Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/md-command-line.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-06-11T01:19:38.000Z","updated_at":"2020-05-19T03:10:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"fd440ffd-e5e5-49f9-bb49-7fbbc7275aa3","html_url":"https://github.com/md-command-line/guide_to_building_structured_bash_programs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/md-command-line/guide_to_building_structured_bash_programs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/md-command-line%2Fguide_to_building_structured_bash_programs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/md-command-line%2Fguide_to_building_structured_bash_programs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/md-command-line%2Fguide_to_building_structured_bash_programs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/md-command-line%2Fguide_to_building_structured_bash_programs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/md-command-line","download_url":"https://codeload.github.com/md-command-line/guide_to_building_structured_bash_programs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/md-command-line%2Fguide_to_building_structured_bash_programs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265402833,"owners_count":23759237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-02T05:05:49.369Z","updated_at":"2026-02-03T09:34:50.428Z","avatar_url":"https://github.com/md-command-line.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# scalable_bash_programs\nWhat you need to know to build structured bash programs. A few lessons learned.\n\n## As often as possible include set on Debug mode for better transparency.\n```bash\n# set -e provides more output that can help with testing your program.\nset -e\n```\n\n## Getting past the first file, calling other scripts:\nRunning a script from afar is easy, \nGet the current directory name: [source](https://www.linuxquestions.org/questions/programming-9/bash-how-to-get-current-workin-directory-92961/)\n```bash\nDIR=${PWD##*/}; echo $DIR; \n# means \"PWD with the first part removed, up to, and including the last slash.\n```\n\n\u003cbr/\u003eThe first challenge a developer runs into is trying to run another script that is nearby the script you are running from afar. \n\nScripts know the location of the person running the script \n\u003cbr/\u003ebut are not automatically self aware of their own location.\n\nThis line of code ensures that your script will know its current location.[source](https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within)\n```bash\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" \u0026\u0026 pwd )\";\n```\nrelative file locations are now accessable\n```bash\nls $DIR/../; \n```\n\n## Calling a script or executable is as simple as:\n./$DIR/script\nopen $DIR/.app #-mac\n\n## Waiting for a script to complete.\nI know this guide is about bash but its worth considering javascript.\nThe most elegant solution I have seen for this might be using javascript promises to await the completion of the program .then(run_the_next_script)\n\nsh-exec is javascript library that is worth checking out.\n\nThere is a way in bash called autoexpect that I am not overly familiar with in bash. [source](https://stackoverflow.com/questions/7197527/bash-script-how-can-i-wait-for-certain-output-from-a-process-then-continue)\n\nFor operations dependent on a user, I have stored information in a hidden file fired a notification every five seconds and every second checked if the file existed.\n\n```bash\nadaptive_wait () { # bash function for macintosh notifications. Checking presence of file every second.\nTIMEOUT=25;\n  until [ -d ~/Library/Screen\\ Savers/$screen$saver ] || [ -d /Library/Screen\\ Savers/$screen$saver ] || [ $TIMEOUT -eq 0 ] ; do\n    if ! ((TIMEOUT % 5)); then\n      osascript -e 'display notification \"To allow for Decision/User Credentials\" with title \"Application Waiting\"';\n    fi\n    sleep 1;\n    TIMEOUT=$[$TIMEOUT-1];\n  done\n}\n```\n\n## Testing, \nCalling functions from another file: [source](https://stackoverflow.com/questions/10822790/can-i-call-a-function-of-a-shell-script-from-another-shell-script)\n```bash\nsource ./file_to_source;\nname_of_function;\n```\n\nRunning multiple tests in one go pass your parameters in with read. [source](https://stackoverflow.com/questions/10822790/can-i-call-a-function-of-a-shell-script-from-another-shell-script)\n```bash\n# Run tests\n# argument table format:\n# testarg1   testarg2     expected_relationship\nsource ./file_we_are_running_function_from;\necho \"The following tests should pass\"\nwhile read -r test\ndo\n    testvercomp $test\ndone \u003c\u003c EOF\n1            1            =\n2.1          2.2          \u003c\n3.0.4.10     3.0.4.2      \u003e\n4.08         4.08.01      \u003c\n3.2.1.9.8144 3.2          \u003e\n3.2          3.2.1.9.8144 \u003c\n1.2          2.1          \u003c\n2.1          1.2          \u003e\n5.6.7        5.6.7        =\n1.01.1       1.1.1        =\n1.1.1        1.01.1       =\n1            1.0          =\n1.0          1            =\n1.0.2.0      1.0.2        =\n1..0         1.0          =\n1.0          1..0         =\nEOF\n\necho \"The following test should fail (test the tester)\"\ntestvercomp 1 1 '\u003e'\n```\n\n## Write to a specific line of another file.\n```bash\n# uses \"?\" as a wildcard inserts into the 9th line the variable pwd3 wiping overidding the line that was previously at that location.\nsed -i '' '9s?.*?'\"$pwd3\"'?' $DIR/.tmp/com.monitor.charge.plist\n```\n\n## Append to the end of a file \n```bash \necho \"hello\" \u003e\u003e test.txt\n```\n\n## Overide file with new contents\n```bash\necho \"hello is gone\\ngoodbye\" \u003e test.txt\"\n```\n\n## For each directory is a useful command.\n```bash\nfor d in ./*/ ; do (cd \"$d\" \u0026\u0026 echo \"$d\" \u0026\u0026 echo \"hi\"); done\n```\n\n## One great attribute bash provides is that you can quickly test everything on terminal in a single line of code \u003cbr/\u003e\nIn bash everything can be a one liner and copied and pasted directly into terminal.\n\n## Use bash when it makes sense to use bash. High Level operating system programs or curl requests.\u003cbr/\u003e\nBash can be used by other languages such as ruby or node-javascript to in a simple way add functionality to your application.\n\n## Do not always use bash. Come up with an Idea first and let that determine the language you choose.\n\n\neverything below from [source](http://tiswww.case.edu/php/chet/bash/bashref.html)\n## Regarding alias usage:\nAliases are expanded when a command is read, not when it is executed. Therefore, an alias definition appearing on the same line as another command does not take effect until the next line of input is read. The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. Aliases are expanded when a function definition is read, not when the function is executed, because a function definition is itself a command. As a consequence, aliases defined in a function are not available until after that function is executed. To be safe, always put alias definitions on a separate line, and do not use alias in compound commands.\n\nFor almost every purpose, shell functions are preferred over aliases.\n\n## Regarding braces vs parameters\n```\n( list )\nPlacing a list of commands between parentheses causes a subshell environment to be created\n\n{ list; }\nPlacing a list of commands between curly braces causes the list to be executed in the current shell context. \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmd-command-line%2Fguide_to_building_structured_bash_programs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmd-command-line%2Fguide_to_building_structured_bash_programs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmd-command-line%2Fguide_to_building_structured_bash_programs/lists"}