0
#!/bin/bash

INPUT="urls.txt"
URL=""

while read URL || [ -n "$URL" ] ;
do
  echo -e "
*************************************************************************************
Scaning \"$URL\" ...
*************************************************************************************\n";
  nmap -v -sV $URL -Pn |tee $URL-$(date +%m%d%y)_$(date +%H%M).log
done < $INPUT

I know that if I just remove || [ -n "$URL" ], the script won't process the last line of $INPUT.

Also, could you please explain me where is the part of the script in which you go to the next line of $INPUT in each step of the while loop?

  • 1
    https://explainshell.com/explain?cmd=while+read+URL+%7C%7C+%5B+-n+%22%24URL%22+%5D%3B+do+echo+%22%24URL%22%3B+done – phuclv Mar 22 '22 at 03:21
  • `read` reads the next line of input each time it runs (which is at the beginning of each iteration of the loop). As for the `-n` part, see ["Shell script read missing last line"](https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line). – Gordon Davisson Mar 22 '22 at 04:30
  • You find this documented, when you do a `man test`. – user1934428 Mar 22 '22 at 05:47
  • @user1934428 `man [` will work as well – phuclv Mar 22 '22 at 06:34
  • @phuclv : I would had expected this too, but interestingly it does not work in my installation (Cygwin). In particular, `man [` does not show me the _test_ man page, but just refers to the page _BASH_BUILTINS(1)_, which does not give any information on this command. This is odd, since both `[` and `test` are bash builtins and at the same time available as external commands, so I would have expected that `man` behaves identical for them. – user1934428 Mar 22 '22 at 06:40

1 Answers1

0

So, final answer would be that [ -n "$STRING" ] will return TRUE if the variable “$STRING” has non-zero length. So what is the magic beyond this?

(1) First of all, what does read VARIABLE do?

It reads the actual line (first character from line to first occurrence of new line reserved character \n or EOF, which is the reserved character for END OF FILE). The thing with this sentence is that it returns TRUE only if the actual line ends with \n, but not with some specific EOF characters (it should, but some text editors use a different reserved character and it won’t work always).

PD: Every time read command is executed, it moves an internal pointer to the next line of $INPUT. So, what happens after read command reads the last line on INPUT (the one that ends with EOF)? It will return FALSE and VARIABLE will be returned empty.

(2) How does the last while iteration takes place?

First take a look at the condition: while read URL || [ -n "$URL" ] ; So, because it is the last iteration, the actual line will end with EOF character. Therefore read URL will return FALSE (because line doesn’t end with \n), but URL won’t be empty, because there is an actual url there. This way, the first term of the while condition will be FALSE, but because URL is not empty, second term will be TRUE, which makes the whole condition to be TRUE. So, last line of INPUT will be processed as it should, despite having a weird EOF character.