Executing a dynamically created command with spaces in shell script - shell

I have to write a script that generates and executes a command with a variable number of arguments containing file names. These file names may contain spaces, and everything must work fine with or without spaces.
For example, this generated command may look like this :
curl --data-urlencode "js_code#/tmp/some folder/data.txt" http://www.someurl.com
If I use a hard coded command and execute it it all runs fine, with and without spaces. If I create the command text in a string variable however, and execute the string contents, it seems the command does not take the quotes into account, using only the first part of the file :
The script (simplified, just imagine the command string is created using complex rules) :
#!/bin/sh
#prepare
command="curl --data-urlencode \"param_value#/tmp/some folder/data.txt\" www.someurl.com"
#execute
$command
The results :
$ ./test.sh
Warning: Couldn't read data from file ""param_value#/tmp/some", this makes an
Warning: empty POST.
curl: (6) Couldn't resolve host 'folder'
I tried different things, switching quotes style, using things like exec, but I could'nt get this to work.
Any help would be appreciated
Thanks
Note : I should add all this testing is done on Cygwin. It may be important regarding path syntax.

You should use eval :
eval "$command"

Have you tried:
command='curl --data-urlencode "param_value#/tmp/some\ folder/data.txt" www.someurl.com'

Related

How to pass variables with special characters into a bash script when called from terminal

Hello all I have a program running on a linux OS that allows me to call a bash script upon a trigger (such as a file transfer). I will run something like:
/usr/bin/env bash -c "updatelog.sh '${filesize}' '${filename}'"
and the scripts job is to update the log file with the file name and file size. But if I pass in a file name with a single quote in its file name then it will break the script and give an error saying "Unexpected EOF while looking for matching `''"
I realize that a file name with a single quote is making the calling command an invalid one since the single quote is messing with the command itself. However I don't want to sanitize the variables if I can help it cause I would like my log to have the exact file name being displayed to easier cross reference it later. Is this possible or is sanitizing the only option here?
Thanks very much for your time and assistance.
Sanitization is absolutely not needed.
The simplest solution, assuming your script is properly executable (has +x permissions and a valid shebang line), is:
./updatelog.sh "$filesize" "$filename"
If for some reason you must use the bash -c, use single quotes instead of double quotes surrounding your code, and keep your data out-of-band from that code:
bash -c 'updatelog.sh "$#"' 'updatelog' "$filesize" "$filename"
Note that only updatelog.sh "$#" is inside the -c argument and parsed as code, and that this string is in single quotes, passed through without any changes whatsoever.
Following it are your arguments $0, $1 and $2; $0 is used when printing error messages, while $1 and $2 go into the list of arguments -- aka $# -- passed through to updatelog.sh.

spaces,',`,/,\,<,>,?,&,| are filtered how to bypass them with Bash commands

i have PHP code use some bash codes which the PHP code can run it, and its have a bug to make RCE in bash,
the command would be "$(id)" command executed as well
but if i execute any other command like "ls -la" its have a space
the space replaced automatically with "-"
i checked the source as well and i found the following chars spaces,',`,/,\,<,>,?,&,| are filtered
how to bypass them and execute command like "wget link" and run it perfect
****UPDATE****
the following code i add as a live example.
send the command in sendcmd function
`https://pastebin.com/raw/1MfR6aic`
This is (example) output from id
uid=1000(ibug) gid=1000(ibug)
Since these characters aren't filtered, you can get an unfiltered space like this:
ID=$(id)
echo${ID:14:1}foo
Now you have space. You can get virtually any character with echo -e and then eval an expression.
I tried your PHP code and found this working:
sendcmd("http://52.27.167.139", "{echo,hello}");
Just wrap then in braces and use commas. The shell will expand the brace to
echo hello

cURL Scraping Wrong Webpage

I am attempting to scrape a webpage that requires a login using curl in the Mac Terminal but can't seem to get it right. I have a cookies.txt file with my login info that I am reading into the command, but I can't get it to scrape the intended page. When I run
curl -b /Users/dwm8/Desktop/cookies.txt -o /Users/dwm8/Desktop/file.txt https://kenpom.com/team.php?team=Duke&y=2002
the contents of file.txt are the webpage data from https://kenpom.com/team.php?team=Duke instead of https://kenpom.com/team.php?team=Duke&y=2002. Is there a fix for this? Thanks for the help.
& is a shell metacharacter that separates commands and indicates the command before it should be run in the background. So, your command:
curl ... https://kenpom.com/team.php?team=Duke&y=2002
gets parsed as two separate commands:
curl ... https://kenpom.com/team.php?team=Duke & # The & means run curl in the background
y=2002 # This just sets a shell variable
In order to get the shell to treat & as part of the argument to curl rather than a command separator, you need to quote it (either single- or double-quotes would work) or escape it with a backslash:
curl ... 'https://kenpom.com/team.php?team=Duke&y=2002'
curl ... "https://kenpom.com/team.php?team=Duke&y=2002"
curl ... https://kenpom.com/team.php\?team=Duke\&y=2002
Oh, and notice that I also escaped the ? in that last example? That's because ? is also a shell metacharacter (specifically, a wildcard). In this case it probably wouldn't cause any trouble, but it's safest to quote or escape it just in case. And since it's hard to keep track of exactly which characters can cause trouble, I'll recommend quoting instead of escaping, and just quoting everything that you're at all unsure about.
You need to wrap url part in quotes.

Difference between typing a shell command, and save it to a file and using `cat myfile` to execute it?

I have an rsync command that works as expected when I type it directly into a terminal. The command includes several --include='blah' and --exclude='foo' type arguments. However, if I save that command to a one-line file called "myfile" and I try `cat myfile` (or, equivalently $(cat myfile)), the rsync command behaves differently.
I'm sure it is the exact same command in both cases.
Is this behavior expected/explainable?
I've found the answer to this question. The point is that the cat command takes the contents of the file and treats it like a string. Any string operators (like the escape operator, ) are executed. Then, the final string output is what is passed to a command via the backticks.
As a solution, I've just made "myfile" a shell script that I can execute rather than trying to use cat.

Run simple programme using unix shell

I'm new to unix and its developing. In my new.sh script I wrote
$USERNAME=user
$PASSWORD=sekrit
echo $USERNAME
and ran new.sh using bash new.sh
But I get the following errors
new.sh: line 1: =user: command not found
new.sh: line 2: =sekrit: command not found
How do I run that command and print the username variable in terminal?
USERNAME is the name of the variable. $USERNAME is the replacement (aka contents, aka value). Since USERNAME is empty, you effectively try to run a command named =user, which is what the error message tells you.
Remove the $ from $USERNAME=... and it will work.
As Jens notes in his answer, the problem is that an assignment to a variable is not prefixed with a $, so:
USERNAME=user
PASSWORD=sekrit
is the way to write what you wanted. You got an error because USERNAME was not set, so after expansion, the shell looked at the command as:
=user
=sekrit
and it could not find such commands on the system (not very surprisingly). However, be aware that if you have previously written:
USERNAME=archipelago
PASSWORD=anchovy
then the lines:
$USERNAME=user
$PASSWORD=sekrit
would have been equivalent to writing:
archipelago=user
anchovy=sekrit
You could see that by running set with no arguments; it would show you the values of all the variables set in the shell. You could search for words such as USERNAME and archipelago to see what happened.
Now you've learned that, forget it. The number of times you'll need to use it is very limited (but it is handy on those rare — very rare — occasions when you need it).
For all practical purposes, don't write a $ on the left-hand side of a variable assignment in shell.

Resources