Bash "while read loop" does not properly recognize variables [duplicate] - bash

This question already has answers here:
bash variable interpolation separate variables by a hyphen or underscore
(3 answers)
Error in string Concatenation in Shell Scripting
(3 answers)
Closed 5 years ago.
I am using MacBook pro terminal to execute a shell script. It loops through a text file and create filenames based on each line in the file.
#!/bin/bash
year=2010
list=list_test.txt
mydir=thisdir
i=1 # counter
while read line
do
echo $i $line
file1=`echo $mydir/file_$year_$line_test.tif`
file2=`echo $mydir/file_$year_$line_test.tif`
echo $file1 $file2
i=$(($i+1))
done < $list
However, the output is peculiar:
1 17019
thisdir/file_.tif thisdir/file_.tif
2 17029
thisdir/file_.tif thisdir/file_.tif
3 17039
thisdir/file_.tif thisdir/file_.tif
Within the loop, bash does not recognize some variables, like "year" which is a global, and "line" which is read from the text file. The text file is as below:
17019
17029
17039
Another script with exactly the same manner works very well. This is mysterious to me now.
Any help or comments are extremely appreciated! Thanks very much!

_ is a valid character for an identifier, but you want to use it as a literal character in the file name. You need to use the full form of parameter expansion, ${x} instead of $x.
(Also, the command substitution isn't necessary.)
file1=$mydir/file_${year}_${line}_test.tif
file2=$mydir/file_${year}_${line}_test.tif

Related

Bash while loop behave differently in file vs direct execution [duplicate]

This question already has answers here:
Loop through an array of strings in Bash?
(21 answers)
Closed 2 years ago.
The following is the sample while loop.
res=()
lines=$'first\nsecond\nthird'
while read line; do
res+=("$line")
done <<< "$lines"
echo $res
When i run this directly in terminal im getting the following out put.
first second third
But when run the same script by saving it to a file. Then im getting the following out put.
first
Why is it behaving differently?
Note: I tested with and without shebang in file. result is same.
If you have a string with embedded newlines and want to turn it into an array split on them, use the mapfile builtin:
$ mapfile -t res <<<$'first\nsecond\nthird'
$ printf "%s\n" "${res[#]}"
first
second
third

Can't manage to give two arguments from a fil to bash script : command not found [duplicate]

This question already has answers here:
Why does a space in a variable assignment give an error in Bash? [duplicate]
(3 answers)
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 3 years ago.
I'm new to bash script, it is interesting, but somehow I'm struggling with everything.
I have a file, separated by tab "\t" with 2 infos : a string and a number.
I'd like to use both info on each line into a bash script in order to look into a file for those infos.
I'm not even there, I'm struggling to give the arguments from the two columns as two arguments for bash.
#/!bin/bash
FILE="${1}"
while read -r line
do
READ_ID_WH= "echo ${line} | cut -f 1"
POS_HOTSPOT= echo '${line} | cut -f 2'
echo "read id is : ${READ_ID_WH} with position ${POS_HOTSPOT}"
done < ${FILE}
and my file is :
ABCD\t1120
ABC\t1121
I'm launching my command with
./script.sh file_of_data.tsv
What I finally get is :
script.sh: line 8: echo ABCD 1120 | cut -f 1: command not found
I tried a lot of possibilities by browsing SO, and I can't make it to divide my line into two arguments to be used separately in my script :(
Hope you can help me :)
Best,
The quotes cause the shell to look for a command whose name is the string between the quotes.
Apparently you are looking for
while IFS=$'\t' read -r id hotspot; do
echo "read id is: $id with position $hotspot"
done <"$1"
You generally want to avoid capturing things into variables you only use once, but the syntax for that is
id=$(echo "$line" | cut -f1)
See also Correct Bash and shell script variable capitalization and When to wrap quotes around a shell variable?. You can never have whitespace on either side of the = assignment operator (or rather, incorrect whitespace changes the semantics to something you probably don't want).
You have a space after the equals sign on lines 5 and 6, so it thinks you are looking for an executable file named echo ABCD 1120 | cut -f 1 and asking to execute it while assigning the variable READ_ID_WH to the empty string, rather than assigning the string you want to the variable.

using command line arguments in loop shell [duplicate]

This question already has answers here:
Brace expansion with a Bash variable - {0..$foo}
(5 answers)
Closed 3 years ago.
I am trying to use command line arguments for arithmetic but cant seem to find any documentation explaining how to do this. As an example if I use:
for i in {$1..$2}
do
echo $i
done
and call
test.sh 1 20
the following output is produced:
{1..20}
instead of
1
2
3
..
20
The following will also work:
declare -a ary='({'$1..$2'})'
for i in "${ary[#]}"; do
echo "$i"
done
Note that declare is as harmful as eval.
You need to check and sanitize the arguments before use.
There's no way to do this properly without the evil eval() with brace expansion in bash.
You can use seq instead :
for i in $(seq $1 $2); do

In shell script, how do I use the contents of a file as a parameter [duplicate]

This question already has answers here:
Need to assign the contents of a text file to a variable in a bash script
(4 answers)
Closed 4 years ago.
Suppose in dir.txt I have the following content:
test-dir
I try to use that as a parameter as follows:
echo dir.txt | cp * $1
I want the above to be the equivalent of:
cp * test-dir
What am I doing wrong?
You are giving the string "dir.txt" to a program that does not accept any input by stdin.
You are looking for the following syntax:
cp * "$(<dir.txt)"
$() runs the command inside parenthesis and substitutes its results in its position in the command line. The < is a shorthand to read a file (a cat would also work). The quotes are to avoid problems with spaces.
You can get content of file to variable:
file1=$(cat dir.txt)
echo $file1
Results:
test-dir

How to read the last characters not ending with a newline from a stream [duplicate]

This question already has answers here:
Reading input files by line using read command in shell scripting skips last line
(5 answers)
Shell script read missing last line
(7 answers)
Closed 4 years ago.
I have a script called test.sh which processes the standard input line by line like this:
#!/usr/bin/env bash
echo "start"
while IFS= read -r line; do
echo "processing[$line]"
done < /dev/stdin
echo "done"
The problem with this is, it doesn't process the characters between the last newline and the eof.
printf $'line 1\nline 2\nlast chars' | test.sh
will output
start
processing[line 1]
processing[line 2]
done
The reason I read line by line is that I need to inspect the first line and in some cases I want to remove it from the output stream.
How can I process these last characters? I've looked into read -n but then I would need to supply how many characters to expect at a maximum and I rather don't build in limits.
Also: I wouldn't know where to put this statement in the while-loop. I'm on the macOS platform.

Resources