{"id":780,"date":"2025-11-06T10:23:24","date_gmt":"2025-11-06T02:23:24","guid":{"rendered":"https:\/\/play.datalude.com\/blog\/?p=780"},"modified":"2025-11-06T10:57:25","modified_gmt":"2025-11-06T02:57:25","slug":"bash-htaccess-file-management-script","status":"publish","type":"post","link":"https:\/\/play.datalude.com\/blog\/2025\/11\/bash-htaccess-file-management-script\/","title":{"rendered":"bash htaccess file management script"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">OK, so its not too hard to  run htpasswd manually, but if you spend a lot of time in your job doing it, it's nice to have a tool to do it more efficiently. This is a menu driven script, which will make a backup of your file, and suggest a random password, which you can choose to use or not. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As always, don't trust everything you read on the internet, and test before you use in anger. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\n# Configuration\nHTACCESS_FILE_DEFAULT=\"\/etc\/nginx\/htpasswd-developers\n\n# Function to display a list of users\ndisplay_users() {\n  echo \"--- Existing Users ---\"\n  # Grep for lines that don't start with # and aren't empty\n  # Then use cut to show only the username before the colon, and number the lines\n  grep -vE '^(#|$)' \"$HTACCESS_FILE\" | cut -d':' -f1 | cat -n\n  echo \"----------------------\"\n}\n\n# Function to perform a backup\nbackup_file() {\n  if &#91; -f \"$HTACCESS_FILE\" ]; then\n    cp \"$HTACCESS_FILE\" \"$HTACCESS_FILE.bak\"\n    echo \"Backup created at $HTACCESS_FILE.bak\"\n  else\n    echo \"No .htpasswd file to back up.\"\n  fi\n}\n\n# Function to generate a random password\ngenerate_password() {\n    tr -cd '&#91;:alnum:]' &lt; \/dev\/urandom | head -c 12\n}\n\n# --- Main Script ---\n\n# Select the .htpasswd file. Suggest the default value, but allow user to type another name\nread -p \"Enter .htpasswd file (default: $HTACCESS_FILE_DEFAULT): \" HTACCESS_FILE\nHTACCESS_FILE=${HTACCESS_FILE:-$HTACCESS_FILE_DEFAULT}\n\n# Ensure the file exists, exit if not\nif &#91; ! -f \"$HTACCESS_FILE\" ]; then\n  echo \"Password file doesn't exist\"\n  exit 1\nfi\n\n# Main menu loop\nwhile true; do\n  echo \"Do you want to:\"\n  echo \"a) Add a user\"\n  echo \"r) Remove a user\"\n  echo \"u) Update a user's password\"\n  echo \"l) List users\"\n  echo \"q) Quit\"\n  read -p \"Enter your choice: \" choice\n\n  case \"$choice\" in\n    a)\n      read -p \"Enter username to add: \" username\n      # Check if the username already exists\n      if grep -q \"^$username:\" \"$HTACCESS_FILE\"; then\n        echo \"Error: User '$username' already exists. Use the 'u' option to update their password.\"\n      else\n        suggested_password=$(generate_password)\n        read -p \"Enter password for '$username' (or press Enter to use suggested: $suggested_password): \" password\n        password=${password:-$suggested_password}\n        \n        backup_file\n        htpasswd -b \"$HTACCESS_FILE\" \"$username\" \"$password\"\n        echo \"User '$username' added.\"\n      fi\n      ;;\n    r)\n      display_users\n      read -p \"Enter reference number of user to remove: \" ref\n      # Use grep and sed to find the line number and get the username\n      username_to_remove=$(grep -vE '^(#|$)' \"$HTACCESS_FILE\" | sed -n \"${ref}p\" | cut -d':' -f1)\n\n      if &#91; -z \"$username_to_remove\" ]; then\n        echo \"Invalid reference number.\"\n      else\n        backup_file\n        # Create a temp file without the user and then replace the original\n        grep -v \"^$username_to_remove:\" \"$HTACCESS_FILE\" > \"$HTACCESS_FILE.tmp\" &amp;&amp; mv \"$HTACCESS_FILE.tmp\" \"$HTACCESS_FILE\"\n        echo \"User '$username_to_remove' removed.\"\n      fi\n      ;;\n    u)\n      display_users\n      read -p \"Enter reference number of user to update: \" ref\n      username_to_update=$(grep -vE '^(#|$)' \"$HTACCESS_FILE\" | sed -n \"${ref}p\" | cut -d':' -f1)\n\n      if &#91; -z \"$username_to_update\" ]; then\n        echo \"Invalid reference number.\"\n      else\n        suggested_password=$(generate_password)\n        read -p \"Enter new password for '$username_to_update' (or press Enter to use suggested: $suggested_password): \" password\n        password=${password:-$suggested_password}\n\n        backup_file\n        htpasswd -b \"$HTACCESS_FILE\" \"$username_to_update\" \"$password\"\n        echo \"Password for user '$username_to_update' updated.\"\n      fi\n      ;;\n    l)\n      display_users\n      ;;\n    q)\n      echo \"Exiting.\"\n      exit 0\n      ;;\n    *)\n      echo \"Invalid option. Please try again.\"\n      ;;\n  esac\n\n  echo \"\"\ndone\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>OK, so its not too hard to run htpasswd manually, but if you spend a lot of time in your job doing it, it's nice to have a tool to do it more efficiently. This is a menu driven script, which will make a backup of your file, and suggest a random password, which you &#8230; <a title=\"bash htaccess file management script\" class=\"read-more\" href=\"https:\/\/play.datalude.com\/blog\/2025\/11\/bash-htaccess-file-management-script\/\" aria-label=\"Read more about bash htaccess file management script\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[144,1,4],"tags":[],"class_list":["post-780","post","type-post","status-publish","format-standard","hentry","category-bash-script","category-it","category-linux"],"_links":{"self":[{"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/posts\/780","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/comments?post=780"}],"version-history":[{"count":3,"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/posts\/780\/revisions"}],"predecessor-version":[{"id":784,"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/posts\/780\/revisions\/784"}],"wp:attachment":[{"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/media?parent=780"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/categories?post=780"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/play.datalude.com\/blog\/wp-json\/wp\/v2\/tags?post=780"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}