So I just need to remove matching pairs in an array. My array consists of a deck of cards. If an element is a pair, for example if the array $sortedHand is: SA DA C9 C8
Because their is a pair of aces in spades and diamonds. I need to remove it from the array $sortedHand
So then the new variable maybe $removedHand would only contain C9 C8. Hope you understand
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 $
declare -a sortedHand
for i
do
hand+=' '${cards[i]}
done
set -- $(printf "%d\n" "$#" | sort -n)
for i
do
sortedHand+=' '${cards[i]}
done
echo The hand is $hand
echo Sorted hand $sortedHand
Edit I have added code
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 $
for i
do
hand+=' '${cards[i]}
done
set -- $(printf "%d\n" "$#" | sort -n)
for i
do
sortedHand+=' '${cards[i]}
done
echo The hand is $hand
echo Sorted hand $sortedHand
for((i=0; i -le ${#hand}; ++i))
do
for((j=0; j -le ${#hand}; ++j))
do
if [ $i == $j ]
then continue
fi
if [ ${hand[i]:1:1} == ${hand[j]:1:1} ]
then continue 2
fi
done
sortedHand+=' '${hand[i]}
done
echo Remaining cards $sortedHand
This is the output I get
turtle.sh 1 2 5 10
The hand is SA HA SK HQ
Sorted hand SA HA SK HQ
./turtle.sh: line 23: ((: i -le 12: syntax error in expression (error token is "12")
Remaining cards SA HA SK HQ
Help please
Another Edit
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 $
for i
do
hand+=' '${cards[i]}
done
set -- $(printf "%d\n" "$#" | sort -n)
for i
do
sortedHand+=' '${cards[i]}
done
echo The hand is $hand
echo Sorted hand $sortedHand
for((i=0; i-le${#sortedHand}; ++i))
do
for((j=0; j-le${#sortedHand}; ++j))
do
if [ $i == $j ]
then continue
fi
if [ ${sortedHand[i]:1:1} == ${sortedHand[j]:1:1} ]
then continue 2
fi
done
remainingHand+=${hand[i]}
done
echo Remaining cards $remainingHand
The outcome of above code
turtle.sh 1 2 5 10
The hand is SA HA SK HQ
Sorted hand SA HA SK HQ
Remaining cards
Thanks for all your help
Also tried your exact code
turtle.sh 1 2 5 10
The hand is SA HA SK HQ
Sorted hand SA HA SK HQ
Remaining cards SA HA SK HQ
Loop through hand and loop through hand again from the current index of the outer loop.
Compare the second letter of the elements and add index to sortedHand if no matches were found.
That would look like this:
cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7)
for i in $# # $# are all passed arguments, if this gives issues try putting quotes around it
do hand+=(cards[i])
done
for((i=0; i < ${#hand[#]}; ++i)) # C style loop, uses i and <, not $i and -le.
do
for((j=0; j < ${#hand[#]}; ++j)) # ${#hand[#]} is the number of elements in the array hand.
do
if [ $i == $j ]
then continue
fi
if [ ${hand[i]:1:1} == ${hand[j]:1:1} ]
then continue 2
fi
done
sortedHand+=(${hand[i]})
done
echo ${hand[#]} # ${hand[#]} is the array in string representation.
echo ${sortedHand[#]}
To delete an element from an array, use the unset command (with quotes to avoid pathname expansion):
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 $)
echo "${cards[#]}" # null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 $
unset 'cards[1]'
echo "{cards[#]}" # null HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 $
Related
My intention with this code is to print all possible combinations between the letters of the alphabet, **including single letters.**I wrote this part of a program from CS50x course (week 2 - crack)
I include the use of '\0' in order to get as well the single letters. It all works well until it starts working on the uppercase letters, after then it will skip '\0' once every two loops. The result is I am missing half of single uppercase letters and I have no idea why it acts this way.
This is an extract of the result I get (this part is correct, notice single letters 'g', 'h', 'i' all get printed):
Blockquote fZ g ga gb gc gd ge gf gg gh gi gj gk gl gm gn go gp gq gr gs gt gu gv gw gx gy gz gA gB gC gD gE gF gG gH gI gJ gK gL gM gN gO gP gQ gR gS gT gU gV gW gX gY gZ h ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz hA hB hC hD hE hF hG hH hI hJ hK hL hM hN hO hP hQ hR hS hT hU hV hW hX hY hZ i ia ib ic
But after a while it starts skipping letters (it prints 'W' and 'Y' but not 'X')
Blockquote VZ W Wa Wb Wc Wd We Wf Wg Wh Wi Wj Wk Wl Wm Wn Wo Wp Wq Wr Ws Wt Wu Wv Ww Wx Wy Wz WA WB WC WD WE WF WG WH WI WJ WK WL WM WN WO WP WQ WR WS WT WU WV WW WX WY WZ Xa Xb Xc Xd Xe Xf Xg Xh Xi Xj Xk Xl Xm Xn Xo Xp Xq Xr Xs Xt Xu Xv Xw Xx Xy Xz XA XB XC XD XE XF XG XH XI XJ XK XL XM XN XO XP XQ XR XS XT XU XV XW XX XY XZ Y Ya
This is the original code:
int main(void)
{
char abc[52] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
char xyz[3];
char null = '\0';
for (int i = 0; i < 52; i++)
{
xyz[0] = abc[i];
xyz[1] = null;
printf("%s ", xyz);
for (int j = 0; j < 52; j++)
{
xyz[1] = abc[j];
printf("%s ", xyz);
}
}
printf("\n");
}'''
With
xyz[1] = abc[j];
you overwrite the null terminator you just set.
Better to initialize the whole array to zero (the null terminator)
char xyz[3] = { '\0' };
Then you don't need to explicitly set a null terminator a second time for the inner loop.
OK, so I moved on to the next week of the course and they introduced an IDE which I used to try on this. As #Weather Vane points out, it works perfectly this time. So I assume the code was not entirely wrong, just somehow the previous sandbox on which I was compiling and running the program may be the problem here. Thanks to all who posted!
What query should use, If I have a data set that I want to transform
From | To | Val1 | Val2 | Val3
123 130 AB DE EF
131 140 WS ED RF
141 145 GT HY JU
and I want to print the following data set in Oracle
ID | Val1 | Val2 | Val3
123 AB DE EF
124 AB DE EF
125 AB DE EF
126 AB DE EF
127 AB DE EF
128 AB DE EF
129 AB DE EF
130 AB DE EF
131 WS ED RF
132 WS ED RF
133 WS ED RF
134 WS ED RF
135 WS ED RF
136 WS ED RF
137 WS ED RF
138 WS ED RF
139 WS ED RF
140 WS ED RF
141 GT HY JU
142 GT HY JU
143 GT HY JU
144 GT HY JU
145 GT HY JU
Assumptions: Your table is called inputs (if not, use your actual table name); the first two columns are called f and t (they can't be called from and to, those are Oracle reserved words); and the f column is unique - meaning, it has no duplicates - and you guarantee that f <= t in all rows:
select f + level - 1 as id, val1, val2, val3
from inputs
connect by level <= t - f + 1
and prior f = f
and prior sys_guid() is not null
;
so I am quite confused right now because I am new to bash and I am not sure how I am going to tackle this problem.
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 H7 D7 C7 S6 H6 D6 C6 S5 H5 D5 C5 S4 H4 D4 C4 S3 H3 D3 C3 S2 H2 D2 C2)
declare -a cardsNamed
for i in "$#"
do
cardsNamed+=' '${cards[i]}
done
echo The hand is $cardsNamed
I need the $cardsNamed array to sort the cards in order of elements of the first array. For example if cardsNamed has SJ HA DK. It would sort to HA DK SJ.
For some background. This is a card game that displays the cards you pick through parsing the arguments and then sorts and discards pairs.
Really appreciate all the help I can get. Thanks
Assuming your arguments are numbers and valid indices to the array, I can think of two ways:
Sort the arguments
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 H7 D7 C7 S6 H6 D6 C6 S5 H5 D5 C5 S4 H4 D4 C4 S3 H3 D3 C3 S2 H2 D2 C2)
for i
do
cardsNamed+=' '${cards[i]}
done
set -- $(printf "%d\n" "$#" | sort -n)
for i
do
cardsNamedSorted+=' '${cards[i]}
done
echo The hand is $cardsNamed
echo The sorted hand is $cardsNamedSorted
You could also do for i in $(printf "%d\n" "$#" | sort -n) instead of using set, if you don't want to overwrite the arguments.
A new array with only selected entries
#!/bin/bash
declare -a cards=(null SA HA DA CA SK HK DK CK SQ HQ DQ CQ SJ HJ DJ CJ ST HT DT CT S9 H9 D9 C9 S8 H8 D8 C8 S7 H7 D7 C7 S6 H6 D6 C6 S5 H5 D5 C5 S4 H4 D4 C4 S3 H3 D3 C3 S2 H2 D2 C2)
declare -a cardsNamedSorted
for i
do
cardsNamed+=' '${cards[i]}
cardsNamedSorted[i]=${cards[i]}
done
echo The hand is $cardsNamed
echo Sorted hand: "${cardsNamedSorted[#]}"
cardsNamedSorted will only contain the specified entries, in the same order as cards.
Notes:
for i without an in <something> is the same as for i in "$#".
You have declared cardsNamed as an array, yet its usage is like a normal variable.
New to using Grep. Basically I have two text files; blacklist.txt and many foo.txt in different directories.
I started off using:
grep -vE "(insert|blacklist|items|here)" foo.txt > filtered_foo.txt
but my blacklist has grown exponentially and so I need to compare the two files instead.
In foo.txt there are four columns with columns 1,2,3 being unique. I want to delete rows where column 4 matches a string in my blacklist.
Sample of a foo.txt
A1 A2 A3 Bob
B1 B2 B3 Anne
C1 C2 C3 Henry
D1 D2 D3 Ted
blacklist.txt
Anne
Ted
Desired output: filtered_foo.txt
A1 A2 A3 Bob
C1 C2 C3 Henry
I have tried different things in grep such as:
grep -vF "'cat blacklist.txt'" foo.txt > filtered_foo.txt
Use the -f option to get the patterns from a file.
grep -vF -f blacklist.txt foo.txt > filtered_foo.txt
I just started using shell programming. I want to automatically change directories and then rename some files in there. Here's my problem: The name of the directories are numbered but directories < 10 are zero-padded (01 02...09). How can I define an array using some sort of sequencing without typing each directory name manually?
This is what I've tried so far:
array = (printf "%.2d " {1..8} {11..27} {29..32} {34..50}) ## should say 01 02 03 ..08 11..27 29..32 34..50
for i in "${array[#]}"
do
echo "dir_a/dir_b/sub$i/dir_c/"
done
However, it doesn't work and the result looks like: "subprintf", "sub%.2s", "sub1" etc.
Can you help me there?
In a next step I want to filter certain numbers in the array, e.g. 03, 09, 10, 28, 33 as these directories don't exist. Is there some easy solution to create such an array without concatenating 5 separate arrays?
Many thanks in advance,
Kati
Is there a need to use arrays? Otherwise, for bash 4, you can do
for i in {01..08} {11..27} {29..32} {34..50}; do
echo "dir_a/dir_b/sub${i}/dir_c/"
done
For an older version of bash you have to add the 0 yourself:
for i in 0{1..8} {11..27} {29..32} {34..50}; do
echo "dir_a/dir_b/sub${i}/dir_c/"
done
Of course, if you want to have an array, you can do
array=({01..08} {11..27} {29..32} {34..50})
or
array=(0{1..8} {11..27} {29..32} {34..50})
You could do this:
declare -a dirs=('01' '02' '03' '04' '05' '06' '07' '08')
echo ${dirs[#]}
01 02 03 04 05 06 07 08
# Make up next sequence
declare -a b=`seq 11 18`
echo ${b[#]}
11 12 13 14 15 16 17 18
# Add sequences together
dirs=("${dirs[#]}" ${b})
echo ${dirs[#]}
01 02 03 04 05 06 07 08 11 12 13 14 15 16 17 18
find [0-9][0-9] -type d | while read dirname
do
if [ $(echo "${dirname}" | sed -n '/01/p') ]
then
cd "${dirname}"
mv foo bar
cd ..
fi
done
Then you can just write another elif and sed check for every directory which contains files you want to rename. I know it's not what you asked for, but it is infinitely simpler. If you're allowed to, I'd also strongly recommend renaming that directory tree, as well.
#/bin/bash
raw=({01..08} {11..27} {29..32} {34..50})
filter=(03 09 10 28 33)
is_in() {
for e in "${#:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
for i in ${raw[#]}; do
is_in $i ${filter[#]} || echo "dir_a/dir_b/sub$i/dir_c"
done
It'll take the numbers in the raw array and exclude every occurance of the ones in the filter array.