I have an assignment from university, where I need to read from a pipe a bash command and exec this command. I am thinking of using the execv* because i can create a buffer by splitting with space as delimiter. The problem is that I can't use the STL library and I can't figure out how this buffer should be created because the size of this buffer is variable. Any suggestions? Thanks in advance
If you do only one pipe commands like below, buffer size 30 is enough,even more
ls -l | wc -l
But you can support multiple pipe commands, you will get a command like bellow, and your buffer size must be enough it
cat index.html | grep ".com" | grep ".splunk." | cut -d "<" -f2 | cut -d ">" -f1 | grep ":" | cut -d":" -f2 | cut -d "/" -f3 | cut -d " " -f1 | grep ".splunk." | cut -d '"' -f1 | sort | uniq
Your buffer size should be 100,I choosed size 100 for my operating system projects like yours, we implemented a terminal, it supports almost everything,multiple pipe,redirection eg...
In addition,I used execvp like below,
execvp(args[0], &args[0]);
Related
I'm sysadmin for couple of webservers deployed with cpanel hosting panel. I'm trying to finish up with a backup script. There are two commands bundled with Cpanel, that will be used in this script. These commands are;
1. whmapi1 modifyacct user=USERNAME BACKUP=[01]
This Command has booleans to set, what it does is either enable or
disable backup for a specific user.
2. /usr/local/cpanel/bin/backup --force
Once backup is enabled for a user/users, then this command starts the
backup process on the server.
So here is my script logic & the script.
#!/bin/bash
Arrays
L=($( comm -23 <(du -h --max-depth=1 /home 2>/dev/null | grep G | awk -F"/" '{print $NF}' | sort | egrep -vw '(home|virtfs)') <(ls -al /var/cpanel/suspended/ | grep -v 'lock' | sort) ))
Above Array contains all the account whose home directories have
exceeded 1GB limit.
S=($(comm -23 <(du -h --max-depth=1 /home 2>/dev/null | egrep -v '(!G|.cp|cP|clamav)' | awk -F"/" '{print $NF}' | sort | egrep -vw '(home|virtfs)') <(ls -al /var/cpanel/suspended/ | grep -v 'lock' | sort) ))
Above Array contains all the account whose home directories are less
than 1GB limit.
whmapi1 modifyacct user=${L[#]} BACKUP=0 && whmapi1 modifyacct user=${S[#]} BACKUP=0
Above command disables backup for all users for start, to start from
scracth.
whmapi1 modifyacct user=${S[#]} BACKUP=1
T
his command enables backup for all accounts whose home dirs are less
than 1 GB
/usr/local/cpanel/bin/backup --force
This command starts backup process for all enabled users.
The logic is, that I want to create backup of small accounts first, and then when it's finished, I'll run it for larger accounts.
PROBLEM: all commands execute successfully when run directly in terminal, but it doesn't when run via a script. Problem occurs at account enabling & disabling.
It either disables all or enables all, and not the partial accounts, as intended by the logic of the script.
Can anyone point out, where & what I'm missing?
Thanks in advance !!
${l[#]} exands to user1 user2 user3 ..., so user=${L[#]} expands to user=user1 user2 user3 ..., if you want to fun foreach user, you need to loop over users.
du_buff=$(du -h --max-depth=1 /home 2>/dev/null)
lock_buff=$(ls -al /var/cpanel/suspended/ | grep -v 'lock' | sort)
L=($(comm -23 <(echo "$du_buff" | grep G | awk -F"/" '{print $NF}' | sort | egrep -vw '(home|virtfs)') <(echo "$lock_buff") ))
S=($(comm -23 <(echo "$du_buff" | egrep -v '(!G|.cp|cP|clamav)' | awk -F"/" '{print $NF}' | sort | egrep -vw '(home|virtfs)') <(echo "$lock_buff") ))
# for every user in L and S
for user in "${L[#]}" "${S[#]}"; do
whmapi1 modifyacct user=$user BACKUP=0
done
# for every user in S
for user in "${S[#]}"; do
whmapi1 modifyacct user=$user BACKUP=1
done
/usr/local/cpanel/bin/backup --force
I am trying to write a script to grab the users from the passwd file
USERS_LIST=( $( cat /etc/passwd | cut -d":" -f1 ) )
the above would do the trick up until now because I only had users with no spaces in their names.
However, this is not the case anymore. I need to be able to resolve usernames that may very well have spaces in their names.
I tried reading line by line the file, but the same problem exists (this is one line but I have indented it for clarity here):
tk=($( while read line ; do
j=$(echo ${line} | cut -d":" -f1 )
echo "$j"
done < /etc/passwd )
)
unfortunately if I try to print the array, the usernames with space will be split in 2 array cells.
So username "named user" , will occupy array [0] and [1] locations.
How can I fix that in sh shell?
thank you for your help!
Arrays are bash (and ksh, and zsh) features not present in POSIX sh, so I'm assuming that you mean to ask about bash. You can't store anything in an array in sh, since sh doesn't have arrays.
Don't populate an array that way.
users_list=( $( cat /etc/passwd | cut -d":" -f1 ) )
...string-splits and glob-expands contents. Instead:
# This requires bash 4.0 or later
mapfile -t users_list < <(cut -d: -f1 </etc/passwd)
...or...
IFS=$'\n' read -r -d '' -a users_list < <(cut -d: -f1 </etc/passwd)
Now, if you really want POSIX sh compatibility, there is one array -- exactly one, the argument list. You can overwrite it if you see fit.
set --
cut -d: -f1 </etc/passwd >tempfile
while read -r username; do
set -- "$#" "$username"
done <tempfile
At that point, "$#" is an array of usernames.
After using bash -x to debug this script, it appears that a problem occurs near $InvalidText, where grep treats the output of InvalidText as separate file names.
The only solution I can think of is to direct the output of InvalidText to a file, then grep that file.. are there any other alternatives?
# find IP address of Invalid user and give the fake name they tried. Loop for all IP addresses
InvalidText=$(grep "Invalid user" syslog.log)
IPInvalidUser=$(grep "Invalid user" syslog.log | awk '{print $NF}' | uniq)
InvalidUserarray=( $IPInvalidUser )
for FAKEHOST in "${InvalidUserarray[#]}"
do
fakeinfo=$(grep ${FAKEHOST} $InvalidText | cut -d: -f5 | awk '{print $3}')
echo -e "Invalid user attempts:\n"
echo -e "$FAKEHOST $fakeinfo"
done
I saw quite a few different solutions to resolve an issue with keeping an array from a pipe however none seemed to do the trick for me, currently my script works correctly however the array "databasesarray" is lost upon "done", how would I go about keeping this information with my complex pipe scheme?
databasesarray=()
N=0
dbs -d 123123 | grep db|awk '{print $2}'|while read db;
do
databasesarray[$N]="$db";
databasesarray[$N]+=$(gdb $db|grep dn);
echo ${N} ${databasesarray[$N]};
N=$(($N + 1));
done
Better and more efficient way of filling up array in a loop:
databasesarray=()
while read -r db; do
databasesarray+=( "$db $(gdb "$db"|grep "dn")" )
done < <(dbs -d 123123 | awk '/db/{print $2}')
Your grep and awk can be combined into one
Instead of pipe with while it better to use process substitution < <(...) syntax
PS: You could use read -a for filling up array:
read -a databasesarray < <(dbs -d 123123 | awk '/db/{print $2}')
I have a file which contains commands similar to:
cat /home/ptay89/test/01.out
cat /home/ptay89/testing/02.out
...
But I only want a few of them executing. For example, if I only want to see the output files ending in 1.out, I can do this:
cat commands | grep 1.out | sh
However, I get the following output for each of the lines in the commands file:
: cannot be loaded - no such file or directoryst/01.out
When I copy and past the commands I want from the file directly, it works fine. Are there better ways of doing this?
You probably have spurious carriage returns in your file (created under Windows?). Use tr instead of cat to remove them:
tr -d '\015' <commands | grep 1.out | sh
Try doing a
grep -e '^cat.*out' commands | grep 1.out | sh
That should ignore any weird characters and take only the ones you need.