1

The following command works when entered directly on the console:

[root@server user]# curl -d 'parameter=170.22.16.14 192.10.2.24 - - [01/Jan/1900:00:00:00 -0300] "GET  /files/notes.txt HTTP/1.1" 200 112061 "-" "Java/1.8.0.160"' -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add

On the other side, I have a bash script addinfo.sh:

#!/bin/bash

tail -n0 -F info.txt | while read LINE; do ins="curl -d 'parameter=$LINE' -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add" echo $ins $ins done

Then I execute the following echo instruction and the output is shown as keeps:

[root@server user]# echo '170.22.16.14 192.10.2.24 - - [01/Jan/1900:00:00:00 -0300] "GET  /files/notes.txt HTTP/1.1" 200 112061 "-" "Java/1.8.0.160"' >> info.txt
[root@server user]# curl -d 'parameter=170.22.16.14 192.10.2.24 - - [01/Jan/1900:00:00:00 -0300] "GET  /files/notes.txt HTTP/1.1" 200 112061 "-" "Java/1.8.0.160"' -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add
curl: option -: is unknown
curl: try 'curl --help' or 'curl --manual' for more information

The HTTP request was not carried out. The following input data cannot be changed:

170.22.16.14 192.10.2.24 - - [01/Jan/1900:00:00:00 -0300] "GET  /files/notes.txt HTTP/1.1" 200 112061 "-" "Java/1.8.0.160"

So what can I do in order to correct the Bash script?

  • 1
    You add variable in single quotes, so it is not interpreted by bash and it's just a string for curl – Romeo Ninov Feb 24 '23 at 14:46
  • In that third code block, where you get the error "curl: option -: is unknown", are you entering that command manually on the shell command line? Or is that the output you get from that script of yours above? – ilkkachu Feb 24 '23 at 15:22
  • Using backticks in 2023 stop me reading this, TL;DR: use $() form... – Gilles Quénot Feb 24 '23 at 15:31
  • 1
    @GillesQuénot, there don't seem to be any backticks there? (Apart from the code block formatting added by AdminBee, that is.) Or am I missing something? – ilkkachu Feb 24 '23 at 15:33
  • My bad, dunno what's happens – Gilles Quénot Feb 24 '23 at 15:35

1 Answers1

1
ins="curl -d 'parameter=$LINE' -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add"

What you're putting in the variable is shell syntax, a command in the form you'd enter on a shell command line (interactively or in a script) for the shell to parse.

$ins

But this doesn't parse the contents of the variable for shell syntax. Instead, it just applies word splitting and globbing to the value and uses the resulting fields as a command name and arguments. That's different from processing syntax elements like quotes, operators (incl. redirections) or expansions (with dollar signs or backticks).

Here it results in the command name and arguments curl, -d 'parameter=170.22.16.14, 192.10.2.24, -, -, etc.

Note that hard quotes there. That's the same as what one would get when running a shell command like

curl -d "'parameter=170.22.16.14" 192.10.2.24 - - etc.

The underlying difference in principle is that the variable is supposed to contain data, and data is not parsed as code. You might want for it to work like that when you're using quotes, but it would also mean that e.g. any command substitutions would also run and, strings looking like them can be present in e.g. command line arguments or filenames. It'd be impossible to process arbitrary strings in any sensible way.

To get it right, don't put code in data, just run the command directly:

tail -n0 -F info.txt | while read LINE; do
    curl -d "parameter=$LINE" -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add
done

or if you want to, store the command in a function first:

f() {
    curl -d "parameter=$1" -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add
}
tail -n0 -F info.txt | while read LINE; do
    f "$LINE"
done

If you want to print the command when running it, you could either use set -x to have the shell print what it actually runs. (Bash would do that in an unambiguous format suitable as input to the shell again, others might produce ambiguous output.)

Modifying the function above:

f() (
    set -x
    curl -d "parameter=$1" -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add
)

Or you could store the whole command in an array, print it and then run it. (this gives ambiguous output, though):

f() {
    cmd=(curl -d "parameter=$1" -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://192.138.1.10:8080/system/add)
    printf "%s " "${cmd[@]}"
    echo
    "${cmd[@]}"
}

See: How can we run a command stored in a variable?

ilkkachu
  • 138,973