Reading input in bash from stdin - bash

This is my input:
99116784 12 12 0 p
99116784 12 12 0
This is the code i have
while read line || [[ -n "$line" ]];
do for var in $line
do echo $var
done
done
If I then print $line in the while, the p gets printed
Just doing echo $var doesnt print or know the p is there, anyone knows why?

I reorganised your code and it works in bash on my Mac.
#!/bin/bash
while read line || [[ -n "$line" ]];
do
for var in $line
do
echo $var
done
done
exit 0
running it
./test.sh
99116784 12 12 0 p
99116784
12
12
0
p
99116784 12 12 0
99116784
12
12
0

Related

numbers as command-line arguments and prints the count

I want to take numbers as command-line arguments and prints the count of
numbers that end with 0, 1, 2, etc. up to 5.
Example:
bash test.sh 12 14 12 15 14
Expected Output:
Digit_ends_with count
0 0
1 0
2 2
3 0
4 2
5 1
Mt Attempt:
read -a integers for i in ${integers[#]} do if [[ grep -o '[0-9]' $i ]] count=$(grep -c $i) if [ "$count" -ge "0" ] then
echo "Digit_ends_with" $i echo -e "Count ""$count" fi fi done
But this is not working. How I can achieve this requirement?
#!/bin/bash
echo "Digit_ends_with count" #print table header
for argument in "$#" #loop over all given arguments
do
current=$(echo "$argument" | tail -c 2 ) #get last digit
if (( "$current" <= 5 )) #check if lower than 6
then
echo "$current" #echo if true
fi
done | sort | uniq -c | sed -E 's/\s+//' | sed -E 's/([0-9]+).?([0-9]+)/\2\t\t\1/' #sort, count, remove leading spaces and switch the fields
Example:
╰─$ ./test.sh 188 182 182 12 13 14 18 15 16 17 18 19 10 0 0 0 0 0 0 0 0 0 0
Digit_ends_with count
0 11
2 3
3 1
4 1
5 1
Would you please try the following:
#!/bin/bash
for i in "$#"; do # loop over arguments
(( count[i % 10]++ )) # index with the modulo 10
done
printf "%s %s\n" "Digit_ends_with" "count" # header line
for (( i = 0; i < 6; i++ )); do # loop between 0 and 5
printf "%d\t\t%d\n" "$i" "${count[$i]}" # print the counts
done
Result of ./test.sh 12 14 12 15 14:
Digit_ends_with count
0 0
1 0
2 2
3 0
4 2
5 1

Create variable within a range of numbers except a list of numbers

I have the following variable with a list of numbers
vlist="1 13 20 21 22 24 25 28 240 131 133 136 138 224"
In the next loop I want to input a number between 1 - 250 except the numbers in vlist
while :; do
echo -en 'Number : ' ; read -n3 cvip ; echo
[[ $cvip =~ ^[0-9]+$ ]] || { echo -e '\nSorry input a number between 1 and 239 except '$vlist'\n' ; continue; }
cvip=$(expr ${cvip} + 0)
if ((cvip >= 1 && cvip <= 250)); then break ; else echo -e '\nNumber out of Range, input a number between 1 and 239 except '$vlist'\n' ; fi
done
Ηow can I enter the list exception inside the if statement range
If using bash, one approach is to store the bad numbers as keys in an associative array and see if that particular key exists when validating a number:
#!/usr/bin/env bash
vlist="1 13 20 21 22 24 25 28 240 131 133 136 138 224"
declare -A nums
for num in $vlist; do
nums[$num]=1
done
while true; do
while read -p "Number: " -r num; do
if [[ ! $num =~ ^[[:digit:]]+$ ]]; then
echo "Input an integer."
elif [[ ${nums[$num]:-0} -eq 1 ]]; then
echo "Input a number between 1 and 250 except '$vlist'"
elif [[ $num -lt 1 || $num -gt 250 ]]; then
echo "Input an integer between 1 and 250"
else
break
fi
done
printf "You successfully inputted %d\n" "$num"
done
The important bit is ${nums[$num]:-0}, which expands to the value of that element of the associative array if that key exists and is not null, or 0 otherwise. As noted by Glenn in a comment, in bash 4.3 or newer, [[ -v nums[$num] ]] works too for testing to see if a given key exists, so [[ ${nums[$num]:-0} -eq 1 ]] in the above could be replaced with it.

How to get specific words by index in a line bash

I have a script that takes parameters such as:
script.sh 1 3
I want to then go through a text file and print out the first and third words from each line. I have simply no idea how to do this. If anyone could help I'd really appreciate it...
This is what I currently have:
counter=0
wordcounter=0
param=$(echo "$3" | tr , " ")
words(){
for word in $1; do
for col in $param; do
if [ $wordcounter -eq $col ]; then
echo $word
fi
done
done
wordcounter=$((wordcounter + 1))
}
eachline() {
newline=$(echo "$1" | tr , " ")
for word in $newline; do
if [ $counter -gt 3 ]; then
echo "$word"
fi
counter=$((counter + 1))
done
if [ $counter -gt 0 ]; then
words "$newline"
fi
counter=$((counter + 1))
}
while read line; do
eachline $line
done < company/employee.txt
Use awk:
$ awk '{print $1 " " $3}' file
for file:
1 2 3 4 5
6 7 8 9 0
Output is:
1 3
6 8
In bash script:
#!/bin/bash
awk_command="{print";
for i in "$#"; do
awk_command="${awk_command} \$${i} \" \"";
done
awk_command="${awk_command}}";
awk "$awk_command" file
With this script you can pass any number of indexes:
For 1 and 2:
$ ./script.sh 1 2
1 2
6 7
For 1, 2 and 5:
$ ./script.sh 1 2 5
1 2 5
6 7 0

Sending a value on script start

trying to make a bash script that sets a value for use later in the script, depending on what I send when I run it;
i.e. ./script.sh 24
code:
### Setting values depending on input
#
# If value is between 7 and 13
if [[ $1 -le 13 || $1 -ge 7 ]]; then
#set value to
VALUE=7
# else if value is between 14 and 29
elif [[ $1 -le 29 || $1 -ge 14 ]]; then
#else set value to
VALUE=14
# else if value is larger than 30
elif [[ $1 -le 30 ]]; then
#Set value to VALUE=30
#else
# echo nope
fi
# This is just for showing what's going on
echo "input: $1"; echo "value: $VALUE"
# Do other stuff here...
But I can't get it to work properly, it only sets "value" to 7, no matter what i send on script start.
Does bash read values in any special order? When I run it with ./script.sh 24 I gives "value=7" but it (in my mind) should be "value=14"
In the first comparison:
$1 -le 13 || $1 -ge 7
You are checking if a value is below 13 or above 7. All natural numbers matches this condition, like: 1 is below 13, 100 is avobe 7, and 10 is below 13 and avobe 7. So you always enter in the first branch.
Maybe you are looking for numbers above 7 AND below 13:
$1 -le 13 && $1 -ge 7

How can I get the exact number of lines in while read loop?

I used a while read loop in shell script to count and number line by line my file.txt. Now I want to give, inside the loop, the exact number of lines, like if I'm command wc -l. Below is my script.
#!/bin/bash
let count=0
while read cdat ctim clat clon
do
h=${ctim:0:2}; # substring hours from ctim
m=${ctim:3:2};
s=${ctim:6:2};
# echo $j
if [[ $h>=11 ]]; then
if [[ $h<=18 ]] && [[ $s<=00 ]]; then
if [[ $m != 01 ]]; then # spaces around "!=" is necessary
echo "$count $LINE" $cdat $ctim $clat $clon
let count=$count+1
fi
fi
fi
done < cloud.txt
exit
And output contains lines like:
0 2014/04/00 14:44:00 26.12 -23.22
1 2014/11/21 16:05:00 19.56 -05.30
2 2014/01/31 13:55:00 02.00 31.10
3 2014/04/00 14:20:00 17.42 12.14
4 2014/07/25 15:30:00 35.25 05.90
5 2014/05/15 12:07:00 23.95 07.11
6 2014/07/29 17:34:00 44.00 17.43
7 2014/03/20 18:00:00 -11.12 -22.05
8 2014/09/21 12:00:00 06.44 41.55
My question is how to find that the output contains 9 lines?
This does not answer your specific question
if [[ $h>=11 ]]; then
if [[ $h<=18 ]] && [[ $s<=00 ]]; then
All of those tests always return true.
The test, [ and [[ commands act differently based on the number of arguments they see.
All those tests have 1 single argument. In that case, if it's a non-empty string, you have a success return code.
Crucial crucial crucial to put whitespace around the operators.
if [[ $h >= 11 ]]; then
if [[ $h <= 18 ]] && [[ $s <= 00 ]]; then
Question for you: what do you expect this test to do? [[ $s <= 00 ]]
Be aware that these are all lexical comparisions. You probably want this instead:
# if hour is between 11 and 18 inclusive
if (( 10#$h >= 11 && 10#$h <= 18 )); then
You already know this value with $count. Since you're counting from 0, the number you want is $count+1.
If I add the command "wc -l" at the end of my loop, I can get exactly what I wanted, means that number of lines (9 lines). But I want to know if there is a way to get it exactly inside the loop, maybe using the same command "wc -l" or not.
#!/bin/bash
let count=0
while read cdat ctim clat clon
do
h=${ctim:0:2}; # substring hours from ctim
m=${ctim:3:2};
s=${ctim:6:2};
if [[ $h>=11 && $h<=17 ]] || [[ $ctim == "18:00:00" ]]; then
echo "$count $LINE" $cdat $ctim $clat $clon
let count=$count+1
fi
done < cloud.txt | wc -l
exit
The result is exactly: 9
But now how to do it inside the loop?

Resources