- How to change group ownership of file
- Get file, directory owner or group for use in bash script
- Get octal permissions of a file
- Convert string to array
- Bash loop
- Bash loop over files in dir
- Executing command over
ssh
-echo "${AD_PASSWORD}" | ssh "${host}" "bash -O extglob -c 'sudo -S -- cp \"/home/${USER}/${file}\" ${dir}/${file}'"
- Touch many files for testing
Last active
February 14, 2021 02:14
-
-
Save AkshayRaj/8eb473ebeaeeccdd6128f17672d127df to your computer and use it in GitHub Desktop.
ParenthesesString min number of operations. Also an exhibition of coding style.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
DC6_GATEWAY="prod-stargate-gateway-legacy-1001.va.opower.it" | |
IAD_GATEWAY="prod-sftp-gateway.iad.opower.it" | |
function copy_files_in_dc6_to_iad { | |
dir=$1 #"/opt/jail/home/zok5/Downloads" | |
files=($(echo "${AD_PASSWORD}" | ssh "${DC6_GATEWAY}" "bash -O extglob -c 'sudo -S -- ls \"${dir}/\"'")) # outermost-() for converting string into array | |
dir_owner=$(echo "${AD_PASSWORD}" | ssh "${DC6_GATEWAY}" "bash -O extglob -c 'sudo -S -- stat -c '%U' ${dir}'") | |
dir_group=$(echo "${AD_PASSWORD}" | ssh "${DC6_GATEWAY}" "bash -O extglob -c 'sudo -S -- stat -c '%G' ${dir}'") | |
# copy file from DC6 to IAD | |
for file in ${files[@]} ; do | |
# Copy from DC6_GATEWAY | |
echo "${AD_PASSWORD}" | ssh "${DC6_GATEWAY}" "bash -O extglob -c 'sudo -S -- cp \"${dir}/${file}\" /home/${USER}/${file}'" | |
scp ${DC6_GATEWAY}:/home/${USER}/${file} ./${local_staging_dir}/${file} | |
# Copy to IAD_GATEWAY | |
scp ./${local_staging_dir}/${file} ${IAD_GATEWAY}:/home/${USER}/${file} | |
echo "${AD_PASSWORD}" | ssh "${IAD_GATEWAY}" "bash -O extglob -c 'sudo -S -- cp \"/home/${USER}/${file}\" ${dir}/${file}'" | |
# Sync Permissions, owner and group | |
echo "${AD_PASSWORD}" | ssh "${IAD_GATEWAY}" "bash -O extglob -c 'sudo -S -- chown '${dir_owner}' ${dir}/${file}'" # Owner of dir will also own files in it | |
echo "${AD_PASSWORD}" | ssh "${IAD_GATEWAY}" "bash -O extglob -c 'sudo -S -- chgrp '${dir_group}' ${dir}/${file}'" # Group of dir will also grp files in it | |
permissions=$(echo "${AD_PASSWORD}" | ssh "${DC6_GATEWAY}" "bash -O extglob -c 'sudo -S -- stat -c '%a' ${dir}/${file}'") # Get current perms from DC6 | |
echo "${AD_PASSWORD}" | ssh "${IAD_GATEWAY}" "bash -O extglob -c 'sudo -S -- chmod $permissions ${dir}/${file}'" # Assign same perms in IAD | |
# remove files from staging directories | |
echo "${AD_PASSWORD}" | ssh "${DC6_GATEWAY}" "bash -O extglob -c 'sudo -S -- rm /home/${USER}/${file}'" | |
echo "${AD_PASSWORD}" | ssh "${IAD_GATEWAY}" "bash -O extglob -c 'sudo -S -- rm /home/${USER}/${file}'" | |
rm ./${local_staging_dir}/${file} | |
done | |
} | |
function identify_dirs_and_start_copying { | |
#dirs=(/opt/jail/home/zok5/Downloads /opt/jail/home/zok5/shared_files) | |
dirs=$(curl -s "https://github.va.opower.it/raw/inbound/file-retrieval-configuration/master/config/dc6/prod-client.yml" | grep arrivalUri | grep prod-stargate-gateway | sed 's/.*opower.it//') | |
for dir in ${dirs[@]} ; do | |
if [[ "${is_dry_run}" -eq 1 ]]; then | |
echo $dir | |
else | |
echo "WET $dir" | |
#copy_files_in_dc6_to_iad ${dir} ###################################################################################### Un comment this line to start transfer | |
fi | |
done | |
# Cleanup local storage after all files are copied | |
rm -rf ${local_staging_dir} | |
} | |
## get AD password | |
if [[ -z ${AD_PASSWORD} ]]; then | |
read -sp $'AD Password: \n' AD_PASSWORD | |
else | |
echo "Using AD_PASSWORD environment variable" | |
fi | |
local_staging_dir=tmp_files | |
if [[ -z ${local_staging_dir} ]]; then | |
mkdir ${local_staging_dir} | |
else | |
echo "Cleaning up local staging directory" | |
rm -rf ${local_staging_dir} | |
mkdir ${local_staging_dir} | |
fi | |
## Confirmation dialogue | |
echo "Start the transfer from DC6 to IAD ?" | |
read -p "(y/n)? [NO will do a dry run] " proceed_with_transfer | |
if [[ "${proceed_with_transfer}" != "${proceed_with_transfer#[Yy]}" ]]; then | |
echo "Are you sure you want to start the transfer??" | |
read -p "(y/n)? " proceed_with_transfer | |
if [[ "${proceed_with_transfer}" != "${proceed_with_transfer#[Yy]}" ]]; then | |
echo "Starting to copy outstanding files from DC6_GATEWAY to IAD_GATEWAY.." | |
is_dry_run=0 | |
identify_dirs_and_start_copying | |
else | |
echo "Aborting.." | |
exit 1 | |
fi | |
else | |
echo "Starting the DRY_RUN" | |
is_dry_run=1 | |
identify_dirs_and_start_copying | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
function usage { | |
cat <<EOF | |
usage: ${0} | |
-w wet_run (optional flag; if not provided then defaults to 0) | |
-c clients (list of client codes separated by space; required) | |
Eg, to simulate a dry run, | |
${0} -c glbx util foo | |
To execute wet run and delete data | |
${0} -w -c glbx util foo | |
EOF | |
} | |
## List of archive servers taken from | |
## https://github.va.opower.it/sysops/puppet/blob/production/parameters/toshi.yaml#L1048-L1059 | |
## Only one new-style-archive-host required; so skipping these hosts - | |
## prod-stargate-sftp-archive-1007.va.opower.it | |
## prod-stargate-sftp-archive-1008.va.opower.it | |
ARCHIVE_HOSTS=" | |
dev-stargate-sftp-archive-1001.va.opower.it | |
test-stargate-sftp-archive-1003.va.opower.it | |
prod-stargate-sftp-archive-new-1001.va.opower.it | |
prod-stargate-sftp-archive-1003.va.opower.it | |
prod-stargate-sftp-archive-1004.va.opower.it | |
prod-stargate-sftp-archive-1005.va.opower.it | |
prod-stargate-sftp-archive-1006.va.opower.it | |
prod-stargate-sftp-archive-1009.va.opower.it | |
prod-stargate-sftp-archive-3002.on.opower.it" | |
CLIENT_DIR_LOCATION="/archive/*" | |
function log_message { | |
local level=$(echo "${1}" | tr [:lower:] [:upper:]) | |
shift | |
local message="${@}" | |
local message=$1 | |
local formatted_date=$(date -u +'%Y-%m-%d %H:%M:%S.%3NZ') | |
if [[ "${is_dry_run}" -eq 1 ]] | |
then | |
local dry_run_notice=" [DRY RUN] " | |
else | |
local dry_run_notice=" " | |
fi | |
echo "${level} [${formatted_date}]${dry_run_notice}${message}" 1>&2 | |
} | |
function log_info { | |
local message="${@}" | |
log_message "INFO" "${message}" | |
} | |
function log_error { | |
local message="${@}" | |
log_message "ERROR" "${message}" | |
} | |
function delete_files_on_host { | |
local client=$1 | |
local host=$2 | |
## check if ${client} has non-alphabetic characters,'_' or '-' | |
if [[ -n $(echo ${client} | tr -d "[a-zA-Z0-9_-]") ]]; then | |
log_error "Client code ${client} is invalid. Aborting.." | |
exit 1 | |
fi | |
## set the value for dir_location | |
local archive_client_dir_location="${CLIENT_DIR_LOCATION}/${client}" | |
## Count no of files to be deleted | |
local no_of_files_to_delete=$(echo "${AD_PASSWORD}" | ssh "${host}" "bash -O extglob -c 'sudo -S -- find \"${archive_client_dir_location}\" -print | egrep -v \"(Your password will expire|No such file or directory|^$)\" | wc -l'") | |
## Delete data | |
log_info "Deleting data for ${client} on ${host}" | |
if [[ "${is_dry_run}" -eq 1 ]]; then | |
log_info "Would have deleted $no_of_files_to_delete files and/or directories from ${archive_client_dir_location}" | |
else | |
echo "${AD_PASSWORD}" | ssh "${host}" 'bash -O extglob -c "sudo -S -- rm -rf ${archive_client_dir_location}"' | |
log_info "Deleted ${archive_client_dir_location}" | |
fi | |
} | |
function loop_over_hosts_for_deletion { | |
for client in ${clients[@]} ; do | |
for host in ${ARCHIVE_HOSTS} ; do | |
delete_files_on_host ${client} ${host} | |
done | |
done | |
} | |
## SCRIPT EXECUTION STARTS HERE - | |
## get AD password | |
if [[ -z ${AD_PASSWORD} ]]; then | |
read -sp $'AD Password: \n' AD_PASSWORD | |
else | |
log_info "Using AD_PASSWORD environment variable" | |
fi | |
## default to a dry run | |
is_dry_run=1 | |
if [ $# -eq 0 ]; then | |
log_error "No arguments supplied !!" | |
usage | |
exit 1 | |
fi | |
## parse options passed to the script. | |
while getopts "wc:" flag; do | |
case $flag in | |
w ) is_dry_run=0 | |
;; | |
c ) clients=("$OPTARG") | |
until [[ $(eval "echo \${$OPTIND}") =~ ^-.* ]] || [[ -z $(eval "echo \${$OPTIND}") ]]; do | |
clients+=($(eval "echo \${$OPTIND}")) | |
OPTIND=$((OPTIND + 1)) | |
done | |
;; | |
?) echo "Invalid option: -$OPTARG" >&2 | |
usage | |
exit 1 | |
;; | |
esac | |
done | |
## show confirm wet_run dialogue | |
if [[ "${is_dry_run}" -eq 1 ]]; then | |
log_info "THIS IS A DRY RUN " | |
log_info "Data will be deleted in archive for the following clients -" | |
for client in "${clients[@]}"; do | |
echo "- ${client}" | |
done | |
loop_over_hosts_for_deletion | |
else | |
log_info "THIS IS A WET RUN !!" | |
log_info "Delete data in archive for the following clients -" | |
for client in "${clients[@]}"; do | |
echo "- ${client}" | |
done | |
read -p "(y/n)? " proceed_with_delete | |
if [[ "${proceed_with_delete}" != "${proceed_with_delete#[Yy]}" ]]; then | |
echo "Deleting client data now.." | |
loop_over_hosts_for_deletion | |
else | |
echo "Aborting.." | |
exit 1 | |
fi | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ValidParentheses { | |
private static final Character OPEN = '('; | |
private static final Character CLOSED = ')'; | |
/** | |
* This function calculates the minimum number of operations it would take, to make a | |
* string containing only parentheses - '(', ')' "valid". | |
* | |
* A valid parentheses string has matching set of open & closed parentheses. | |
* | |
* In this context, an operation can be either of the two things - | |
* 1. Adding an open parentheses to the string | |
* 2. Adding a closed parentheses to the string | |
* The parentheses could be placed anywhere within the string, such as to make it valid. | |
* | |
* @param parenthesesString the string to validate | |
* @return the minimum number of operations it would take to make the string valid again. | |
* | |
* ### Big-O complexity | |
* - Time : O(n) -> n is the length of the string | |
* - Space : O(1) -> constant space allocation | |
*/ | |
static int minOperations(String parenthesesString) { | |
int stringLength = parenthesesString.length(); | |
// ### APPROACH : | |
// To find min number of operations required to "validate" a parentheses string, | |
// we have to find the following two numbers - | |
// 1. number of unmatched open parentheses | |
// 2. number of unmatched closed parentheses | |
/* | |
* 1. Find Unmatched Open Parentheses | |
* -> Iterate from "end of the string" ~> "start of the string" | |
* -> For each count of open parentheses, we increment the count of `openParentheses` | |
* -> For each count of closed parentheses, we decrement the count of `openParentheses` | |
* -> Anytime the count of `openParentheses` goes above 0, | |
* : we increment the count of `unmatchedOpenParentheses | |
* : reset `openParentheses` to 0 | |
*/ | |
int openParentheses = 0; | |
int unmatchedOpenParentheses = 0; | |
for (int charIndex = stringLength - 1; charIndex >= 0; charIndex--) { | |
Character parentheses = parenthesesString.charAt(charIndex); | |
if (parentheses.equals(OPEN)) { | |
openParentheses++; | |
if (openParentheses > 0) { | |
unmatchedOpenParentheses++; | |
openParentheses = 0; | |
} | |
} | |
else if (parentheses.equals(CLOSED)) { | |
openParentheses--; | |
} | |
} | |
/* | |
* 2. Find Unmatched Closing Parentheses | |
* -> Iterate from "start of the string" ~> "end of the string" | |
* -> For each count of closed parentheses, we increment the count of `closedParentheses` | |
* -> For each count of open parentheses, we decrement the count of `closedParentheses` | |
* -> Anytime the count of `closedParentheses` goes above 0, | |
* : we increment the count of `unmatchedClosedParentheses | |
* : reset `closedParentheses` to 0 | |
*/ | |
int closedParentheses = 0; | |
int unmatchedClosedParentheses = 0; | |
for (int charIndex = 0; charIndex < stringLength; charIndex++) { | |
Character parentheses = parenthesesString.charAt(charIndex); | |
if (parentheses.equals(CLOSED)) { | |
closedParentheses++; | |
if (closedParentheses > 0) { | |
unmatchedClosedParentheses++; | |
closedParentheses = 0; | |
} | |
} | |
else if (parentheses.equals(OPEN)) { | |
closedParentheses--; | |
} | |
} | |
return unmatchedOpenParentheses + unmatchedClosedParentheses; | |
} | |
public static void main(String[] args) { | |
UnitTest.assertEquals(2, minOperations( ")(")); | |
UnitTest.assertEquals(0, minOperations( "()")); | |
UnitTest.assertEquals(4, minOperations("))((")); | |
UnitTest.assertEquals(0, minOperations("()()")); | |
UnitTest.assertEquals(0, minOperations("(())")); | |
UnitTest.assertEquals(4, minOperations(")())((")); | |
UnitTest.assertEquals(5, minOperations(")))((")); | |
} | |
static class UnitTest { | |
public static void assertEquals(int expected, int actual) { | |
if (expected != actual) { | |
throw new RuntimeException(String.format("Expected value [%d] is not equal to actual value[%d].", expected, actual)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment