shell: strange string concatenation behavior [duplicate] - bash

This question already has answers here:
Remove carriage return in Unix
(21 answers)
Closed 6 years ago.
I write a scipt like this:
#!/bin/bash
while read line
do
echo line ${line}
pdbfile=${line}.pdb
echo pdbfile ${pdbfile}
done < myfile
The result is:
line pdb8mhtA
.pdbfile pdb8mhtA
While it is supposed to be
line pdb8mhtA
pdbfile pdb8mhtA.pdb
What's wrong with this? Why the string concatenation does not work? And why the strange dot at the beginning of the line?
I replace with pdbfile=${line}'.pdb'. That does not change the result.

The "string goes to the beginning of the line" is symptomatic of a carriage return in your $line that you can among many other ways remove with a tr pipe to your file:
while IFS= read -r line
do
echo "line ${line}"
pdbfile=${line}.pdb
echo "pdbfile ${pdbfile}"
done < <(tr -d '\r' <file)

I've tried your script and it works fine for me:
./testConcat
line pdb8mhtA
pdbfile pdb8mhtA.pdb
btw you could try to "preserve" the "."
while read line
do
echo line ${line}
pdbfile=${line}\.pdb
echo pdbfile ${pdbfile}
done < myfile
as you can see the result is the same
./testConcat
line pdb8mhtA
pdbfile pdb8mhtA.pdb

Related

Appending file content to a String variable in loop within a bash file is not working

I am passing a text file to a bash while running. Text file has contents I want to supply to a java program as argument. Text file has each content in a new line. The contents print fine within the loop but I need to create a concatenated string with all the contents to pass to java program and appending to a string variable in loop is not working.
This is how the program looks like:
#!/bin/bash
args=""
for var in $(cat payments.txt)
do
echo "Line:$var"
args+="$var "
done
echo "$args"
It prints:
Line: str1
Line:str2
str2 // args should have appended values of each line but it got only last line
File looks like:
str1
str2
Can anyone suggests what I am doing wrong here?
Thanks
Edit: the issue was due to \r\n line endings.
for var in $(cat payments.txt) is a nice example of useless use of cat. Prefer a while loop:
#!/bin/bash
args=""
while IFS= read -r var; do
args+="$var "
done < payments.txt
echo "$args"
But instead of looping, which is not very efficient with bash, you could as well use a bash array:
$ declare -a args=($(< payments.txt))
$ echo "${args[#]}"
str1 str2
"${args[#]}" expands as separate words. Use "${args[*]}" to expand as a single word . If your line endings are \r\n (Windows) instead of \n (recent macOS, GNU/Linux), the \r will interfere. To remove the \r before printing:
$ echo "${args[#]%$'\r'}"
Your first echo is printing out the combination and not storing it in a new variable. Try:
#!/bin/bash
args=""
for var in $(cat payments.txt)
do
echo = "Line:$var" # this line prints but doesn't alter $var
args+="Line:$var2 " #add Line: in here
done
echo "$args"

How to compare a variable to a string in bash? [duplicate]

This question already has answers here:
How do I compare two string variables in an 'if' statement in Bash? [duplicate]
(12 answers)
Closed 2 years ago.
here is how i tried it
while IFS= read line
do
var=$(cut -d ":" -f 3 $line)
if [ "$var" = "L2" ]
then :here is my action:
fi
done < myfile.txt
What i want to do is read a file line by line, read the third word of each line, and do a special action if the third word = a certaine string, i've tried a lot of syntax but it doesn't work. i've also tried to echo "$var" just to see if my variable get the right value, and it does. i don't know what to do anymore
It is better to use double brackets for if condition & for String comparison double equals (==)
And the line which has "cut" command wouldn't have worked. Please find below the corrected code which is working.
while IFS= read line
do
echo "Line is $line"
var=`echo $line | cut -d ":" -f 3`
echo $var
if [[ "$var" == "L2" ]]
then
echo "Some Action"
fi
done < myfile.txt

Reading a string variable in shell bash line by line and get a number of each line

I wanna do what the title says. In addition it would be desirable to skip the first line. I have this code
#!/bin/bash
output="This\nis 3\na 7\n2 string"
if echo "$output" | grep -q "no"; then #Just looking for substring "no"
echo "No running jobs were found";
else
#read < $output #Skip first line
while read line #read the output line by line
do
jobID = grep -o '[0-9]*' line #Take the number (JobID) of each line
echo $jobID #Use the ID to stop the job
done <<< "$output"
fi
But doesn't wotk. Any ideas? Thanks in advance.
I modified your input string called "output" by adding a number in the first field (line), to demonstrate that that field gets discarded:
#!/bin/bash
output="Th4is\nis 3\na 7\n2 string"
IFS='\'
words=(${output//[!0-9\\]/})
printf "%s\n" "${words[#]:1}"
Forget about the above version, it works on literal \n ...
#!/bin/bash
output="Th4is
is 3\n
a 7
2 string"
tmp=(${output//[!0-9]/ })
printf "%d\n" "${tmp[#]:1}"
3
7
2
that should do

Parsing .csv file in bash, not reading final line

I'm trying to parse a csv file I made with Google Spreadsheet. It's very simple for testing purposes, and is basically:
1,2
3,4
5,6
The problem is that the csv doesn't end in a newline character so when I cat the file in BASH, I get
MacBook-Pro:Desktop kkSlider$ cat test.csv
1,2
3,4
5,6MacBook-Pro:Desktop kkSlider$
I just want to read line by line in a BASH script using a while loop that every guide suggests, and my script looks like this:
while IFS=',' read -r last first
do
echo "$last $first"
done < test.csv
The output is:
MacBook-Pro:Desktop kkSlider$ ./test.sh
1 2
3 4
Any ideas on how I could have it read that last line and echo it?
Thanks in advance.
You can force the input to your loop to end with a newline thus:
#!/bin/bash
(cat test.csv ; echo) | while IFS=',' read -r last first
do
echo "$last $first"
done
Unfortunately, this may result in an empty line at the end of your output if the input already has a newline at the end. You can fix that with a little addition:
!/bin/bash
(cat test.csv ; echo) | while IFS=',' read -r last first
do
if [[ $last != "" ]] ; then
echo "$last $first"
fi
done
Another method relies on the fact that the values are being placed into the variables by the read but they're just not being output because of the while statement:
#!/bin/bash
while IFS=',' read -r last first
do
echo "$last $first"
done <test.csv
if [[ $last != "" ]] ; then
echo "$last $first"
fi
That one works without creating another subshell to modify the input to the while statement.
Of course, I'm assuming here that you want to do more inside the loop that just output the values with a space rather than a comma. If that's all you wanted to do, there are other tools better suited than a bash read loop, such as:
tr "," " " <test.csv
cat file |sed -e '${/^$/!s/$/\n/;}'| while IFS=',' read -r last first; do echo "$last $first"; done
If the last (unterminated) line needs to be processed differently from the rest, #paxdiablo's version with the extra if statement is the way to go; but if it's going to be handled like all the others, it's cleaner to process it in the main loop.
You can roll the "if there was an unterminated last line" into the main loop condition like this:
while IFS=',' read -r last first || [ -n "$last" ]
do
echo "$last $first"
done < test.csv

How to extract values from a string on ksh (korn shell)

I have the following input
MyComposite[2.1], partition=default, mode=active, state=on, isDefault=true, deployedTime=2012-05-07T15:35:22.473-07:00
MessageManager[1.0], partition=default, mode=active, state=on, isDefault=true, deployedTime=2012-05-07T15:37:14.137-07:00
SimpleApproval[1.0], partition=default, mode=active, state=on, isDefault=true, deployedTime=2012-05-07T15:28:39.599-07:00
and I have a script that parses the input line by line from a file but I don't have a clue on how I could extract individual parameters from each line into local variables so I can perform additional processes
So far I'm trying the following:
#!/bin/ksh
file="output"
compositeName="foo" ci=0
# while loop while read line do
# display line or do somthing on $line
if echo "$line" | egrep -q '\[[0-9]*\.[0-9]*\].*?(mode=active).*?
(state=on)' then compositeName=$( echo "$line" | egrep '[0-9]*' )
echo "$compositeName"
#echo "$line"
fi
done <"$file"
I'm somwhow lookint to extract only two values from this string, the first word and the float between brackets
ie:
name = MyComposite
version = 2.1
any ideas?
I'm not sure if those line numbers are in the file or not. If not, you can do this:
#!/usr/bin/env ksh
while IFS="," read nameVersion line; do
name="${nameVersion%%\[*}"
version="${nameVersion//*\[+([0-9.])\]*/\1}"
print "name=$name version=$version"
done < "$file"
If the line numbers are in the file, change the name assignment in the above script to name="${nameVersion//+([0-9]).+( )+(*)\[*/\3}"

Resources