-1

I'm having an issue in something that seems to be a rookie error, but I can't find a way to find a solution.

I have a bash script : log.sh which is :

#!/bin/bash
echo $1 >> log_out.txt

And with a file made of filenames (taken from the output of "find" which names is filesnames.txt and contains 53 lines of absolute paths) I try :

./log.sh $(cat filenames.txt)

the only output I have in the log_out.txt is the first line. I need each line to be processed separately as I need to put them in arguments in a pipeline with 2 softwares. I checked for :

  • my lines being terminated with /n
  • using a simple echo without writing to a file
  • all the sorts of cat filenames.txt or (< filenames.txt) found on internet

I'm sure it's a very dumb thing, but I can't find why I can't iterate more than one line :(

Thanks

Bratten
  • 31
  • 5
  • 1
    you'll need to show us (in a greatly reduced example) what does your input(s) look like and what do you need for output. What you have so far will just copy the first filename (not it's contents) to the `log_out.txt`. Good luck. – shellter Oct 22 '18 at 20:57
  • 1
    what are you trying to do? why not just `cat filenames.txt >> logout.txt` – karakfa Oct 22 '18 at 20:59
  • Because actually it's a log of a more complicated bash I use. But even the simplest output doesn't work – Bratten Oct 22 '18 at 21:04
  • @shellter it's basically the output of a find function to a text file so it's : /home/p11/data/bamfiles/bamfile1.srt.bam etc until 54 – Bratten Oct 22 '18 at 21:06
  • @Barmar I'm sorry but I think it's not the same issue. My issue is that my file is not iterated to the end, not the fact I have an issue in the way the output is given – Bratten Oct 22 '18 at 21:09
  • 3
    You're only echoing the first argument. If you don't quote the variable, that's just the first word in the file. – Barmar Oct 22 '18 at 21:10

3 Answers3

1

It is because your ./log.sh $(cat filenames.txt) is being treated as one argument.

while IFS= read -r line; do
 echo "$line";
done < filenames.txt

Edit according to: https://mywiki.wooledge.org/DontReadLinesWithFor

Edit#2:

  • To preserve leading and trailing whitespace in the result, set IFS to the null string.
  • You could simplify more and skip using explicit variable and use the default $REPLY

Source: http://wiki.bash-hackers.org/commands/builtin/read

Karol Flis
  • 311
  • 2
  • 12
  • 1
    Just, as a side note, include that [dont read lines with for](https://mywiki.wooledge.org/DontReadLinesWithFor) and [how to read file line by line in bash](https://mywiki.wooledge.org/BashFAQ/001). Also escaping is important, probably op means `"${i}"` – KamilCuk Oct 22 '18 at 21:33
  • Thanks, can I with while IFS send that to my bash script? (it's more complicated than just an echo) Thanks ! – Bratten Oct 22 '18 at 22:01
  • Of course. Instead of echo "$line" you have to use that "$line" variable as an argument to your script: ./log.sh "$line" – Karol Flis Oct 22 '18 at 22:05
0

You need to quote the command substitution. Otherwise $1 will just be the first word in the file.

./log.sh "$(cat filenames.txt)"

You should also quote the variable in the script, otherwise all the newlines will be converted to spaces.

echo "$1" >> log_out.txt

If you want to process each word separately, you can leave out the quotes

./log.sh $(cat filenames.txt)

and then use a loop in the script:

#!/bin/bash
for word in "$@"
do
    echo "$word"
done >> log_out.txt

Note that this solution only works correctly when the file has one word per line and there are no wildcards in the words. See mywiki.wooledge.org/DontReadLinesWithFor for why this doesn't generalize to more complex lines.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks I nevertheless have a new issue. Admitting I do a "echo "${1} is the file" I have : file1 file2 ... file 54 is the file I was expected to have the string added to each line. It causes me an issue because I use those paths as arguments for softwares, and it doesn't work anymore :/ thanks ! – Bratten Oct 22 '18 at 21:58
  • What's the issue with that? – Barmar Oct 22 '18 at 22:00
  • It sounds like you need a loop – Barmar Oct 22 '18 at 22:00
  • I indeed would like to use every file to be sent as an argument to 2 software which are in line (the second one needs the output of the first) for the 54 files – Bratten Oct 22 '18 at 22:02
  • I've updated the answer, but you really need to put these details in the question, not just a comment. – Barmar Oct 22 '18 at 22:05
  • Thanks it seems to works awesomely. I've updated the question. – Bratten Oct 22 '18 at 22:10
  • Kamil Cuk pointed below out why this won't be the best solution: https://mywiki.wooledge.org/DontReadLinesWithFor https://mywiki.wooledge.org/BashFAQ/001 – Karol Flis Oct 22 '18 at 22:21
  • @KarolFlis it's not a general solution, but it sounds like his file just has one word per line so it will work here. – Barmar Oct 22 '18 at 23:44
0

You can iterate with each line.

#!/bin/bash
for i in $*
do
  echo $i >> log_out.txt
done