This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 6 years ago.
Having trouble getting this to exit the loop and perhaps I don't understand the while loop well enough to get it to stop. This is what I'm typing in my command line. I expect it to stop at 10.
c=1; while : [[$c -le 10]]; do df -Th; echo "$c"; date; c=`expr $((c+=1))`; sleep 6; done
I've already read article but it didn't seem to help: bash while loop won't stop itself
Final code:
c=1; while [[ $c -le 10 ]]; do df -Th; echo "$c"; date; c=$((c+=1)); sleep 6; done
The final code required removing the : and adding between the [[$c and 10]]
In bash, spaces are important. Replace:
: [[$c -le 10]]
With
[[ $c -le 10 ]]
What went wrong
When bash encounters
: [[$c -le 10]]
it executes the command : with three arguments, [[$c, -le, and 10]]. This is not what you want. First, : is the no-op command: regardless of its arguments, it does nothing. Second, if you want to run the [[ test command, it needs, as shown above, spaces around it.
Alternatives
There are several ways to loop something 10 times in bash. For one:
$ for c in {1..10}; do echo "$c"; done
1
2
3
4
5
6
7
8
9
10
For another:
$ for ((c=1;c<=10;c++)); do echo "$c"; done
1
2
3
4
5
6
7
8
9
10
Related
So as an input, i get echo [number]. For example: echo 5.
I need to get as output the sequence of numbers from 1 to [number].
So if I get 5 as input, I need: 1 2 3 4 5 (all on a separate line).
I know I can use seq 5 to get 1 2 3 4 5 but the issue is that I need to use pipes.
So the final command should be like this: echo 5 | seq [number] which should give 1 2 3 4 5 as output. My issue is that I don't know how to get the output from echo as my input for seq.
Assuming that echo 5 is an example replacement of an unknown program that will write a single number to stdout and that this output should be used as an argument for seq, you could use a script like this:
file seqstdin:
#!/bin/sh
read num
seq "$num"
You can use it like
echo 5 | ./seqstdin
to get the output
1
2
3
4
5
You can also write everything in a single line, e.g.
echo '5'| { read num; seq "$num"; }
Notes:
This code does not contain any error handling. It uses the first line of input as an argument for seq. If seq does not accept this value it will print an error message.
I did not use read -r or IFS= because I expect the input to be a number suitable for seq. With other input you might get unexpected results.
You can use the output of the echo command as follows:
seq $(echo 5)
In case you're dealing with a variable, you might do:
var=5
echo $var
seq $var
I need to merge several files, removing redundant lines among files, while keeping redundant lines within files. A schematic representation of my files is the following:
File1.txt
1
2
3
3
4
5
6
File2.txt
6
7
8
8
9
File3.txt
9
10
10
11
The desired output would be:
1
2
3
3
4
5
6
7
8
8
9
10
10
11
I would prefer to get a solution either in awk, or in bash or in R language. I searched the web for solutions and, though there were plenty of them* (please find some examples below), there were all removing duplicated lines regardless of the fact that they were located within or outside files.
Thanks in advance.
Arturo
Examples of previous solutions removing redundant lines both within and outside files:
https://unix.stackexchange.com/questions/50103/merge-two-lists-while-removing-duplicates
https://unix.stackexchange.com/questions/457320/combine-text-files-and-delete-duplicate-lines
https://unix.stackexchange.com/questions/350520/awk-combine-two-big-files-and-remove-duplicated-lines
https://unix.stackexchange.com/questions/257467/merging-2-files-and-keeping-the-one-duplicate
With your shown samples, could you please try following. This will NOT remove redundant lines within files but will remove them file wise.
awk '
FNR==1{
for(key in current){
total[key]
}
delete current
}
!($0 in total)
{
current[$0]
}
' file1.txt file2.txt file3.txt
Explanation: Adding detailed explanation for above.
awk ' ##Starting awk program from here.
FNR==1{ ##Checking condition if its first line(of each file) then do following.
for(key in current){ ##Traverse through current array here.
total[key] ##placing index of current array into total(for all files) one.
}
delete current ##Deleting current array here.
}
!($0 in total) ##If current line is NOT present in total then do following.
{
current[$0] ##Place current line into current array.
}
' file1.txt file2.txt file3.txt ##Mentioning Input_file names here.
Here's a trick adding on to https://stackoverflow.com/a/15385080/3358272 using diff and its output format. There is likely a presumption of "sorted" here, untested.
out=$(mktemp -p .)
tmpout=$(mktemp -p .)
trap 'rm -f "${out}" "${tmpout}"' EXIT
for F in ${#} ; do
{ cat "${out}" ;
diff --changed-group-format='%>' --unchanged-group-format='' "${out}" "${F}" ;
} > "${tmpout}"
mv "${tmpout}" "${out}"
done
cat "${out}"
Output:
$ ./question.sh F*
1
2
3
3
4
5
6
7
8
8
9
10
10
11
$ diff <(./question.sh F*) Output.txt
(Per markp-fuso's comment, if File3.txt had two 9s, this would preserve both.)
How to calculate X power Y in the unix shell script where value of Y is being supplied by a loop eg. Y=1 to 5. It means I would like to calculte (X^Y)
In bash you could do:
$ for i in {1..5}; do printf "$((2 ** $i))\n"; doneprintf "$((2 ** $i))\n"; done
2
4
8
16
32
Many shells however do not support raise to power operation and in
such situations you need to use bc:
$ for i in $(seq 5); do printf "%s\n" "$(echo "2 ^ $i" | bc)"; done
2
4
8
16
32
I have a script where the sql output of the function is multiple rows (one column) and I'm trying to loop through those for loop function but can't get to seem to get it to work...
rslt=sqlquery {}
echo $rslt
1
2
3
4
for i in $rslt
do
echo "lvl$i"
done
but for the loop...I keep getting this back four times
lvl1
2
3
4
where as I want to get this back...
lvl1
lvl2
lvl3
lvl4
how do I get that?
In order to get the needed result in your script you need to take $rslt under double quotes ". This will ensure that you are not loosing the new lines \n from you result which you are expecting to have in the loop.
for i in "$rslt"
do
echo "lvl$i"
done
To loop over the values in a ksh array, you need to use the ${array[#]} syntax:
$ set -A rslt 1 2 3 4
$ for i in ${rslt[#]}
> do
> echo "lvl$i"
> done
lvl1
lvl2
lvl3
lvl4
If I have an array:
x=( a:1 b:2 c:3 )
How can I split each element of the array on the colon? I'm trying to do this in order to form an associative array.
I've tried several variations on this, but none seem to work:
print -l ${(s,:,)x}
Is this possible? If so, what am I missing?
Ok - further thinking got me to this solution, that might probably be applicable to the problem behind the question asked:
Loop through the array x!
> x=(a:1 b:2 c:3)
> typeset -A z
> for i in $x; do z+=(${(s,:,)i}); done
> echo $z
1 2 3
> echo ${z[a]}
1
I hope that's more helpful than the first answer(s) :-)
Since x is an array, you shouldn't forget the [#], i.e. print ${(s,:,)x[#]}; thus your code becomes print -l ${(s,:,)x[#]}; but the solution is still another step:
> typeset -A z
> x="a:1 b:2 c:3"
> z=($(echo ${(s,:,)x}))
> echo $z[a]
1
The assignement to the associative array is done with the output of the echo statement.
To clarify further and include your original example x:
> typeset -A z
> x=(a:1 b:2 c:3)
> z=($(echo ${(s,:,)x[#]}))
> echo ${z[a]}
1
> echo ${z[b]}
2
(edit: switched thoughts midwriting :-D, should make more sense now)
(edit 2: striked brainf*rt - similarities between zsh and bash aren't as broad as I assumed)
typeset -A x will make x an associative array
$ typeset -A x
$ x=( a 1 b 2 c 3 )
$ echo $x[a]
1
$ echo $x[c]
3
$ x[d]=5
$ echo $x[d]
5
But i don't know how to split on the colon if you need to start from the string "a:1 b:2 c:3".