Iterate an array with different pipe-arguments - arrays

I have an Array like this:
ARRAY=(one two three four five)
And I want to Ilterate this Array in a for loop. But when I read the Array I want to change the output. Like this:
on
tw
thre
fou
fiv
So my question is, how do I do that? I got something like that:
for (( i=0; i<${ARRAYLENGTH}; i++ ));
do
echo "$({ARRAY[$i]} | rev | cut -c 2- | rev)"
done
But It doesn't Work. It Interpretes my pipe argumentes as an echo output.
What can I do?

Try this, I think this should work.
pipea[0]="awk -F[=,] '{print \$2}' | sed '/^\s*$/d'"
pipea[1]="awk -F[=,] '{print \$2}' | sed '/^\s*$/d' | cut -d ' ' -f2"
pipea[2]="awk -F[=,] '{print \$2}' | sed '/^\s*$/d' | cut -d ' ' -f1"
for (( i=0; i<${int}; i++ ));
do
echo "
dn: cn=$(${ldapquery[$i]} | eval ${pipea[0]}),ou=mydomain,dc=saturday,dc=int
objectClass: inetOrgPerson
objectClass: top
cn: $(${ldapquery[$i]} | eval ${pipea[0]})
sn: $(${ldapquery[$i]} | eval ${pipea[1]})
givenName= $(${ldapquery[$i]} | eval ${pipea[2]})
telephoneNumber $(${ldapquery[$i]} | eval ${pipea[2]})"
done

Related

Bash trim some of the text [duplicate]

This question already has answers here:
Printing the last column of a line in a file
(11 answers)
Closed 1 year ago.
I have an output that looks like this
root#machine:path# someapp report | grep Lost
Lost Workers: 0
How can I grep only the digit at the end?
Thanks
Like this:
someapp report | grep -i lost | tr -s ' ' | cut -d' ' -f4
Run app, pipe STDOUT through tr to remove runs of spaces, cut the new string using a space and then select the 4th field
test:
echo " Lost Workers: 0" | tr -s ' ' | cut -d' ' -f4
Combine search and parse with sed:
echo ' Lost Workers: 0' | sed -n '/Lost/ s/.*[[:blank:]]//p'
Pipelines that look like grep | cut ... or grep | tr | cut or similar are almost always better off using awk:
$ printf 'foo\nLost Workers: 0\nbar\n' | awk '/Lost/{print $NF}'
0

diff two arrays each containing files paths into a third array (for removal)

In the function below you will see notes on several attempts to solve this problem; each attempt has a note indicating what went wrong. Between my attempts there is a line from another question here which purports to solve some element of the matter. Again, I've added a note indicating what that is supposed to solve. My brain is mush at this point. What is the stupid simple thing I've overlooking?
function func_removeDestinationOrphans() {
readarray -d '' A_Destination_orphans < <( find "${directory_PMPRoot_destination}" -type f -print0 )
for (( i = 0 ; i < ${#A_Destination_orphans[#]} ; i++ )) ; do
printf '%s\n' "→ ${A_Destination_orphans[${i}]}" # path to each track
done
printf '%b\n' ""
# https://stackoverflow.com/questions/2312762/compare-difference-of-two-arrays-in-bash
# echo ${Array1[#]} ${Array2[#]} | tr ' ' '\n' | sort | uniq -u ## original
# Array3=(`echo ${Array1[#]} ${Array2[#]} | tr ' ' '\n' | sort | uniq -u `) ## store in array
# A_Destination_orphans_diff=(`echo "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" | tr ' ' '\n' | sort | uniq -u `) # drops file path after space
# printf "%s\0" "${Array1[#]}" "${Array2[#]}" | sort -z | uniq -zu ## newlines and white spaces
# A_Destination_orphans_diff=($( printf "%s\0" "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" | sort -z | uniq -zu )) # throws warning and breaks at space but not newline
# printf '%s\n' "${Array1[#]}" "${Array2[#]}" | sort | uniq -u ## manage spaces
# A_Destination_orphans_diff=($( printf '%s\n' "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" | sort | uniq -u )) # breaks at space and newline
# A_Destination_orphans_diff="($( printf '%s\n' "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" | sort | uniq -u ))" # creates string surrounded by ()
# A_Destination_orphans_diff=("$( printf '%s\n' "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" | sort | uniq -u )") # creates string
# A_Destination_orphans_diff=($( printf '%s\n' ${A_Destination_dubUnders[#]} ${A_Destination_orphans[#]} | sort | uniq -u )) # drops file path after space
for (( i = 0 ; i < ${#A_Destination_orphans_diff[#]} ; i++ )) ; do
printf '%s\n' "→ ${A_Destination_orphans_diff[${i}]}" # path to each track
done
printf '%b\n' ""
for (( i = 0 ; i < ${#A_Destination_orphans_diff[#]} ; i++ )) ; do
echo # rm "${A_Destination_orphans_diff[i]}"
done
func_EnterToContinue
}
This throws warning and breaks at space but not newline because you build the array with direct assignment of syntax construct. When an entry contains spaces, it also splits break to a new entry.
A_Destination_orphans_diff=($( printf "%s\0" "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" | sort -z | uniq -zu ))
To avoid the issue of the method above, you can mapfile/readarray a null delimited entries stream.
mapfile -t -d '' A_Destination_orphans_diff < <(
printf "%s\0" "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" |
sort -z |
uniq -zu
)
In case your shell version is too old to support mapfile you can perform the same task with IFS=$'\37' read -r -d '' -a array.
$'\37' is shell's C-Style string syntax with octal code 37, which is ASCII 31 US for Unit Separator:
IFS=$'\37' read -r -d '' -a A_Destination_orphans_diff < <(
printf "%s\0" "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" |
sort -z |
uniq -zu |
xargs -0 printf '%s\37'
)
To remove all files not present in A_Destination_dubUnders array you could:
func_removeDestinationOrphans() {
find "${directory_PMPRoot_destination}" -type f -print0 |
sort -z |
join -z -v1 -t '' - <(printf "%s\0" "${A_Destination_dubUnders[#]}" | sort -z) |
xargs -0 echo rm
}
Use join or comm to find elements not present in one list and present in another list. I am usually wrong about -v1, so try with -v2 if it echoes the elements from wrong list (I do not understand if you want to remove files present in A_Destination_dubUnders list or not present, you did not specify that).
Note that function name() is a mix of ksh and posix function definition. Just name() {. See bash hackers wiki obsolete
Here is the working version with modifications thanks to suggested input from the first two respondents (thanks!).
function func_removeDestinationOrphans() {
printf '%s\n' " → Purge playlist orphans: " ""
printf '%b\n' "First we will remove any files not present in your proposed playlist. "
func_EnterToContinue
bash_version="$( bash --version | head -n1 | cut -d " " -f4 | cut -d "(" -f1 )"
if printf '%s\n' "4.4.0" "${bash_version}" | sort -V -C ; then
readarray -d '' A_Destination_orphans < <( find "${directory_PMPRoot_destination}" -type f -print0 ) # readarray or mapfile -d fails before bash 4.4.0
readarray -t -d '' A_Destination_orphans_diff < <(
printf "%s\0" "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" |
sort -z |
uniq -zu
)
else
while IFS= read -r -d $'\0'; do
A_Destination_orphans+=( "$REPLY" )
done < <( find "${directory_PMPRoot_destination}" -type f -print0 )
IFS=$'\37' read -r -d '' -a A_Destination_orphans_diff < <(
printf "%s\0" "${A_Destination_dubUnders[#]}" "${A_Destination_dubUnders[#]}" "${A_Destination_orphans[#]}" |
sort -z |
uniq -zu |
xargs -0 printf '%s\37'
)
fi
if [[ ! "${A_Destination_orphans_diff[*]}" = '' ]] ; then
for (( i = 0 ; i < ${#A_Destination_orphans_diff[#]} ; i++ )) ; do
rm "${A_Destination_orphans_diff[i]}"
done
fi
}
If you would like to see the entire Personal Music Player sync script, you can find that via my GitHub.

Shell Remove lower versions from array

I have the following array:
ARRAYNAME=(value_1.21.zip value_1.22.zip valueN_0.51.zip valueN_0.52.zip valueM_3.52)
I want to remove the lower versions of the same element and to have the following array:
ARRAYNAME=(value_1.22.zip valueN_0.52.zip valueM_3.52)
In this moment I am using this approach to remove the same elements
ARRAYNAMESORT=$(tr ' ' '\n' <<< "${ARRAYNAME[#]}" | sort -u | tr '\n' ' ')
but I am stuck in removing the lower versions. Does anyone has an idea how to achieve this?
Based on the text structure [Name]_[version].zip
ARRAYNAME=($(printf '%s\n' "${ARRAYNAME[#]}" | awk '{print $1,$1}' | cut -d'_' -f2- | sort -n | sed 1d | awk '{print $2}' | paste -s))
Explanation:
print all array elements printf '%s\n' "${ARRAYNAME[#]}"
duplicate the name in two column awk '{print $1,$1}'
remove left text from the first column cut -d'_' -f2-
sort then remove smallest one which is in the first line sort -n | sed 1d
get the second column the make it serial awk '{print $2}' | paste -s

create arrays from for loop output

I'm trying to understand what I'm doing wrong here, but can't seem to determine the cause. I would like to create a set of arrays from an output for a for loop in bash. Below is the code I have so far:
for i in `onedatastore list | grep pure02 | awk '{print $1}'`;
do
arr${i}=($(onedatastore show ${i} | sed 's/[A-Z]://' | cut -f2 -d\:)) ;
echo "Output of arr${i}: ${arr${i}[#]}" ;
done
The output for the condition is as such:
107
108
109
What I want to do is based on these unique IDs is create arrays:
arr107
arr108
arr109
The arrays will have data like such in each:
[oneadmin#opennebula/]$ arr107=($(onedatastore show 107 | sed 's/[A-Z]://' | cut -f2 -d\:))
[oneadmin#opennebula/]$ echo ${arr107[#]}
DATASTORE 107 INFORMATION 107 pure02_vm_datastore_1 oneadmin oneadmin 0 IMAGE vcenter vcenter /var/lib/one//datastores/107 FILE READY DATASTORE CAPACITY 60T 21.9T 38.1T - PERMISSIONS um- u-- --- DATASTORE TEMPLATE CLONE_TARGET="NONE" DISK_TYPE="FILE" DS_MAD="vcenter" LN_TARGET="NONE" RESTRICTED_DIRS="/" SAFE_DIRS="/var/tmp" TM_MAD="vcenter" VCENTER_CLUSTER="CLUSTER01" IMAGES
When I try this in the script section though I get output errors as such:
./test.sh: line 6: syntax error near unexpected token `$(onedatastore show ${i} | sed 's/[A-Z]://' | cut -f2 -d\:)'
I can't seem to figure out the syntax to use on this scenario.
In the end what I want to do is be able to compare different datastores and based on which on has more free space, deploy VMs to it.
Hope someone can help. Thanks
You can use the eval (potentially unsafe) and declare (safer) commands:
for i in $(onedatastore list | grep pure02 | awk '{print $1}');
do
declare "arr$i=($(onedatastore show ${i} | sed 's/[A-Z]://' | cut -f2 -d\:))"
eval echo 'Output of arr$i: ${arr'"$i"'[#]}'
done
readarray or mapfile, added in bash 4.0, will read directly into an array:
while IFS= read -r i <&3; do
readarray -t "arr$i" < <(onedatastore show "$i" | sed 's/[A-Z]://' | cut -f2 -d:)
done 3< <(onedatastore list | awk '/pure02/ {print $1}')
Better, back through bash 3.x, one can use read -a to read to an array:
shopt -s pipefail # cause pipelines to fail if any element does
while IFS= read -r i <&3; do
IFS=$'\n' read -r -d '' -a "arr$i" \
< <(onedatastore show "$i" | sed 's/[A-Z]://' | cut -f2 -d: && printf '\0')
done 3< <(onedatastore list | awk '/pure02/ {print $1}')
Alternately, one can use namevars to create an alias for an array with an arbitrarily-named array in bash 4.3:
while IFS= read -r i <&3; do
declare -a "arr$i"
declare -n arr="arr$i"
# this is buggy: expands globs, string-splits on all characters in IFS, etc
# ...but, well, it's what the OP is asking for...
arr=( $(onedatastore show "$i" | sed 's/[A-Z]://' | cut -f2 -d:) )
done 3< <(onedatastore list | awk '/pure02/ {print $1}')

Concat Two Command Result in File

I have two commands:
cat BIG_DATAfinal.txt | grep "STATUS" | awk '{print $5}'
cat BIG_DATAfinal.txt | grep "start" | awk '{print $3}' | sed 's/time;//g'
I want concat this two command in a file.
example:
STATUS REPORT FOR JOB: CargaDestino
Generated: 2016-06-17 10:52:14
Job start time;2015-03-30 13:11:45
Job end time;2016-06-17 10:52:14
Job elapsed time;10677:40:29
Job status;99 (Not running)
The expected result would be:
CargaDestino;2015-03-30
Thanks a lot!
For example:
a=`cat BIG_DATAfinal.txt | grep "STATUS" | awk '{print $5}'`
b=`cat BIG_DATAfinal.txt | grep "start" | awk '{print $3}' | sed 's/time;//g'`
echo "$a;$b"
You can do this with a single awk program:
awk -v OFS=";" '
/STATUS/ {status=$5}
/start/ {split($3, a, /;/); start=a[2]}
status && start {print status, start; status=start=""}
' BIG_DATAfinal.txt
If the output looks like ;2015-03-30o, then your file has \r\n line endings, and you should do this:
sed 's/\r$//' BIG_DATAfinal.txt | awk -v OFS=";" '
/STATUS/ {status=$5}
/start/ {split($3, a, /;/); start=a[2]}
status && start {print status, start; status=start=""}
'

Resources