I'm trying to use a for loop like this, where the range consists of letters, both uppercase and lowercase. The problem is, bash doesn't differentiate uppercase and lowercase when it's within a range. How do I make it case sensitive? TIA.
for s in {a..z,A..Z}
do
echo ${s}
done
If you want the letters in that order, just use:
for s in {a..z} {A..Z}
There's no requirement that bash only allows a single brace expansion per line.
The two forms currently allowed are mutually exclusive, being either a selection (of two or more) or a range:
{<val1>,<val2>[,...]}
{<from>..<to>[..<incr>]}
The brace expression {a..z,A..Z} simply expands, using the first form, to the two words (not ranges):
a..z
A..Z
Looks like you got the syntax wrong.
$ echo $BASH_VERSION
3.2.25(1)-release
$ echo {a..k} {A..K}
a b c d e f g h i j k A B C D E F G H I J K
$ echo {a..k,A..K}
a..k A..K
Related
I am having troubles with the arithmetic expressions in a bash file (a unix file .sh).
I have the variable "total", which consists of a few numbers separated by spaces, and I want to calculate the sum of them (in the variable "dollar").
#!/bin/bash
..
dollar=0
for a in $total; do
$dollar+=$a
done
I know I am missing something with the arithmetic brackets, but I couldn't get it to work with variables.
Wrap arithmetic operations within ((...)):
dollar=0
for a in $total; do
((dollar += a))
done
There are a number of ways to perform arithmetic in Bash. Some of them are:
dollar=$(expr $dollar + $a)
let "dollar += $a"
dollar=$((dollar + a))
((dollar += a))
You may see more on the wiki. If you need to handle non-integer values, use a external tool such as bc.
I have seen this notation in bash:
a=${b[c--]}
or also
a[++b]=$c
or the other way around:
a[b++]=$c
but if I execute it on the command line nothing happens.
OSX#26:~ $ a[++b]=2
OSX#27:~ $ echo ${a[++b]}
OSX#28:~ $
What is the use of this notation ?
Edit:
I am asking about this notation. As I have seen it it is a variable, because of the $ in front. But ++ does remind me of increment, so I am confused. Is this some sort of variable increment ?
c-- is an arithmetic expression, it means "return the value of c and then decrement it by 1". ${b[n]} denotes the n-th element of the array b (where the first element has index 0). Expressions inside the square brackets are interpreted as arithmetic (with some exceptions like *, #, '1' etc.) Let's try it:
b=(x y z)
c=2
a=${b[c--]}
echo $a $c # Outputs: z 1
so c-- returns 2, but sets c to 1. b[2], i.e. z, is then assigned to a.
++c is similar to c--, but it adds 1 to c before returning its value.
I have many files with many entries (one entry per line) which I have to filter through a sequence of greps and seds. The lines are of the form
a
x, y
u --> v, w
s --> p, q, r
One the steps is splitting up the lines containing --> such that the left-hand side and each of the comma-separated entries on the right side (of which there can be arbitrary many) end up on different lines. I.e., the above lines should become:
a
x, y
u
v
w
s
p
q
r
Separating the left side from the right side is quickly done:
echo "u --> v, w" | sed 's/\(.\+\)\s*\-\->\s*\(.\+\)/\1\n\2/'
Gives me
u
v, w
But this seems to be a dead end in that I cannot then pipe this on to splitting on the comma, since that would also split the x, y.
So, I am wondering if there is a way to completely split up such lines in a sed command, or do I have to turn to, e.g., awk (or just go to Python)? It would be preferable to keep this a bash pipe sequence.
awk '/-->/ {gsub(/-->|,/,RS)}1' inputfile|column -t
a
x, y
u
v
w
s
p
q
r
OR as Anubhav suggested to avoid pipe:
awk '/-->/ {gsub(/[ \t]*(-->|,)[ \t]*/ , ORS)} 1' inputfile
Using awk you can do this:
awk -F'[ \t]*-->[ \t]*' -v OFS='\n' '{gsub(/,[ \t]*/, OFS, $2)} 1' file
a
x, y
u
v
w
s
p
q
r
You can do this by creating a command group when you match -->. In this group, you replace --> with newline, print up to the newline, discard the portion you printed, then replace commas in the remainder:
#!/bin/sed -f
/\s*-->\s*/{
s//\n/
P
s/.*\n//
s/,\s*/\n/g
}
Results:
a
x, y
u
v
w
s
p
q
r
Alternatively, in GNU sed, you could use the T command to skip processing of the right-hand side unless you match and replace the -->:
#!/bin/sed -f
s/\s*-->\s*/\n/
Tend
P
s/.*\n//
s/,\s*/\n/g
:end
This produces the same output, as required.
I've assumed throughout that you don't want to split any commas on the left-hand side, so that
foo, bar --> baz
becomes
foo, bar
baz
If that's not the case (perhaps if you know there will be no comma to the left of -->), then you don't need P or s/.*\n//, and the script is as simple as
/\s*-->\s*/!n
s//\n/
s/,\s*/\n/g
I have a big text file, each line containing a sentence.
I want to use grep (or something similar in batch) to find sentences where word b occurs exactly or not exactly (some word(s) between them) after word a.
I don't want grep to return a sentence like this:
f g s b d a
because b is not after a but I want to return a sentence like
f g a d m s b f
because b is after a.
It is OK to return sentences where a is both after and before b:
s a s b s a s
I also don't want sentences with only a or b.
I just want the sentences where b is after a (something can be in the middle).
I can easily do it with Python but I want to use the beauty of bash.
Try to do that:
grep "a.*b" file
About substitution of free occurances: can we have a substitution of an entire expression(function, application), or just of a variable:
Example:
Current expression \x.\y.(y, z)
Expression to be replaced: \y.(y z) with p so we will have \x.p.
Is it possible?
Yes, it is possible. One way is to consider the substitution of occurrences. An occurrence is a string over the set {1,2,3}, and for every lambda-term M, the sub-expression M/u at occurrence u is defined as:
M/[] = M
M/0u = N/u, if M=\x. N
M/1u = P/u, if M=PQ
M/2u = Q/u, if M=PQ
(I use the symbol [] to denote the empty string.)
Now define the substitution M[u := N] as the term obtained from replacing the occurrence u with N in M. I've seen this kind of substitution in some of P.-L. Curien work.