1

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

Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
Chanchal
  • 11
  • 2
  • 1
    you might want to try `args=$(echo $( – Fravadona Feb 03 '22 at 10:07
  • 1
    @Fravadona Very nice. Note that echo is however a bit risky when the input is not known. Try with a file that starts with `-e \c`, for instance. – Renaud Pacalet Feb 03 '22 at 10:19
  • @RenaudPacalet you're right, it all depends on the content of payments (numbers?). Given how OP is concatenating args (adding a space at the end), `echo` can be replaced with `printf '%s '` – Fravadona Feb 03 '22 at 10:25
  • @Fravadona Yes, I'd personally prefer `printf`. I don't like `echo`. – Renaud Pacalet Feb 03 '22 at 10:32
  • `for line in $(cat file) ...` doesn't work in general. See [Bash Pitfalls #1 (for f in $(ls *.mp3))](https://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29). [Shellcheck](https://www.shellcheck.net/) identifies this problem. – pjh Feb 03 '22 at 11:12
  • The most likely cause of the problem is that the input file, `payments.txt`, has CR-LF (Windows) line termination. See the first suggestion in the "Before asking about problematic code" section of the [Stack Overflow 'bash' Info page](https://stackoverflow.com/tags/bash/info). – pjh Feb 03 '22 at 11:18
  • This is a duplicate of [Concat a line with a string in bash](https://stackoverflow.com/q/67920216/4154375), and many others. – pjh Feb 03 '22 at 11:35

2 Answers2

1

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'}"
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • I have the same output as the original one having only the last value. #!/bin/bash while IFS= read -r line; do args="$args $line" done < payments.txt echo "$args" – Chanchal Feb 03 '22 at 10:16
  • Strange. I cannot reproduce this here. With a file containing two lines (`str1` and `str2`) I get `str1 str2`. Are you sure you typed exactly this? – Renaud Pacalet Feb 03 '22 at 10:22
  • Suggested lines in above comment are doing the same thing, printing only one value! – Chanchal Feb 03 '22 at 10:43
  • There must be something wrong with your input file or the way you use this. If it really contains several lines it is impossible that `declare -a args=($(< payments.txt)); echo "${args[@]}"` prints only one. My guess: you put all this in a script file, execute it and type `echo "$args"` yourself on the command line. If you do so it is not the same `args` variable that you use: the `args` variable of the script disappeared and the one you `echo` comes from the parent shell. – Renaud Pacalet Feb 03 '22 at 10:48
  • Do not put all this in a script file. Try to type the two last proposed commands yourself on the command line and tell us what you see. We'll package all this in a script after it has been fully tested and validated on the command line. – Renaud Pacalet Feb 03 '22 at 10:50
  • They are printing only last line on command line too. payments.txt file has 2 lines let's str1 on first line and str2 on second line. All the code tried so far in .sh file and the commands typed on command line are doing the same thing, printing only 2'nd line! – Chanchal Feb 03 '22 at 11:03
  • Sorry, I do not understand how this is possible. Did you copy-paste exactly the two lines? Are you 100% sure that the input file is the correct one? Did you try `cat payments.txt` as a third command to check this last point? – Renaud Pacalet Feb 03 '22 at 11:12
  • Could it be that you `echo "$args"` or `echo "${args[0]}"`, instead of `echo "${args[@]}"`? – Renaud Pacalet Feb 03 '22 at 11:28
  • Yes, I copied pasted the exact 2 lines , they referred to echo ${args[@]}. input file is the correct one. cat payments.txt prints both the lines. – Chanchal Feb 03 '22 at 13:16
  • Sorry, I don't understand how this is possible and I cannot reproduce this behavior. Moreover, as you have the same strange behavior with 2 completely different solutions I suspect something specific to your setup or input file but I have no idea. Hopefully somebody else will have an idea and be able to help you. – Renaud Pacalet Feb 03 '22 at 13:58
  • he may have `\r\n` line endings; `\r` would then be part of the data and `str2` will overwrite `str1` when printing – Fravadona Feb 03 '22 at 14:21
  • BTW, in this case `printf '%s\n' "${args[@]}"` would have shown the desired output ;-) – Fravadona Feb 03 '22 at 14:29
  • @Fravadona Of course! That's it. Windows line endings, thanks a lot. I should have thought about it. And no, `printf '%s\n' "${args[@]}"` would print on consecutive lines while the OP wants a space-separated output. – Renaud Pacalet Feb 03 '22 at 14:31
  • oh, that indeed was the problem. I created the text file in notepad++ and then transferred it to linux. It had used \r\n by default which was causing overwriting! After I made changes to use \n, it started working. Thanks a lot for the solution and thanks to everyone else too for their suggestions:) – Chanchal Feb 03 '22 at 14:37
0

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"
  • I don't need to append text "Line:" while appending. That was just used in echo to see if I am getting each line value right. I need args variable which should have each of these variable concatenated having space in between. Purpose is to prepare this to pass to java program as argument. Can you please let me know what is wrong in original line to prepare args and why does it not have variables concatenated? – Chanchal Feb 03 '22 at 10:03