Execute transliterated string in Bash - linux

I want to execute a bash script from a string, say "echo TEST!" for example.
So I could go like this:
eval "echo TEST!"
Problem is, the string is transliterated in UTF-16LE to shorten the char count for golf purpose (it doesn't shorten the byte count but it's not a problem in the given context), so my actual string is "捥潨吠卅⅔".
I know how to transliterate it back, for example if I do this:
echo 捥潨吠卅⅔|iconv -tUCS2
it prints:
echo TEST!
But when I want to execute from the string, it doesn't work.
I tried this for example:
eval 捥潨吠卅⅔|iconv -tUCS2
but it fails miserably.
Could someone help me?
Note: I usually never use Bash so sorry if the question is really dumb.

You can use command expansion to capture the string for eval:
eval "$(echo 捥潨吠卅⅔|iconv -tUCS2)"
If you are golfing, you can further shorten it with backtics, here strings, and if the resulting command does not contain shell syntax, you can skip eval:
`iconv -tUCS2<<<捥潨吠卅⅔`

It fails because eval expects a commnd or an expression to execute, instead you have to use echo -e in order to pipe text to iconv.

Related

linux bash, passing paramenters using a varible issue

I am trying to use a variable to store the parameters, here is the simple test:
#!/bin/bash
sed_args="-e \"s/aaaa/bbbb/g\""
echo $sed_args`
I expected the output to be
-e "s/aaaa/bbbb/g"
but it gives:
"s/aaaa/bbbb/g"
without the "-e"
I am new to bash, any comment is welcome. Thanks, maybe this is already answered somewhere.
You need an array to construct arguments dynamically:
#!/usr/bin/env bash
sed_args=('-e' 's/aaaa/bbbb/g')
echo "${sed_args[#]}"
When you use the variable without double quotes, it gets word split by the shell even before echo sees the value(s). Then, the bash's builtin echo interprets -e as a parameter for itself (which is normally used to turn on interpretation of backslash escapes).
When you double quote the variable, it won't be split and will be interpreted as a single argument to echo:
echo "$sed_args"
For strings you don't control, it's safer to use printf as it doesn't take any arguments after the format string:
printf %s "$string"

Replacing $ with \$ in string variable

I my bash script, I have a string variable with a $ sign it, and the it isn't escaped. It looks like this:
x="hello $world"
Obviously, when I echo "$x", the output is hello, since $world is being interpreted as a variable. My goal is to modify the string to be hello \$world. I tried several techniques, listed below. None of them seem to be working:
y="$(echo "$x" | sed 's/\$/z/g')" (outputs hello)
y="$(echo "$x" | sed 's/$/z/g')" (outputs hello z, even though I didn't escape \ in sed)
Even tried Bash's native string replacement through:
y=${x//\$/z} (outputs hello)
I realize that I could easily do any of these if the string weren't stored in a variable, but the way my script works, this string will be stored in a variable first, so I need to figure out how to add the \ after that. I don't care if I create a new copy of the string or edit the same string.
The assignment (with $world empty or undefined) is the same as writing
x="hello "
Nothing you do to $x will see a $ in there, unless you add it from outside.
Perhaps you meant instead:
x='hello $world'
You can use BASH:
x='hello $world'
echo "${x//\$/\\$}"
hello \$world

Quote argument strings Shell

Can I quote arguments that have spaces or special chars in the command line? If not, how is this handled. We have one argument that is a multiword string. I'm sure this has been asked many times, but I cant find it.
./myscript name=bob occupation=guy who does stuff
You can use quotes. Something like:
$ var='abc def'
$ echo "$var"
abc def
You can read more here.
Your case example (note I'm calling the script that needs the multiword string from the another script in this example):
sh ./test.sh 'this is a test'
test.sh contains echo $1 and prints this is a test. Hope this solution works.

Protecting arguments containing spaces from eval

In order to get eval to work on commands that contain spaces inside one of the parameters, I have only found this to work so far:
eval 'sed 's/foo/foo'" "'bar/g' filename'
In a hypothetical program where users would enter a command and then the command and arguments to be fed to eval, this isn't a very elegant or robust solution. Are there any other ways to run the eval command so that the interface for my_command can be a little more user friendly? The following is an example of how the program accepts arguments now.
my_command 'sed 's/foo/foo'" "'bar/g' filename'
I would like the interface to work something like this:
my_command sed 's/foo/foo bar/g' filename
edit:
I'll try asking a different question:
How do I get bash to read input from the command line literally? I want the exact input to be preserved, so if there are quotes I want to keep them. I can accomplish what I want to do by using egrep to read from file and then sanitizing the input, like so:
egrep '/.*/' filename |
sed 's/\(.*\)['"'"']\(.*\) \(.*\)['"'"']\(.*\)/\1'"\'"'\2" "\3'"\'"'\4/g'
with "filename" containing this line
sed 's/foo/foo bar/g' file
this gives me the desired output of:
sed 's/foo/foo" "bar/g' file
Problem here is that I can't echo "$#" because bash interprets the quotes. I want the literal input without having to read from file.
Original question
For your preferred use-case, you'd simply write (inside my_command):
"$#"
to execute the command as given.
Your eval line is odd:
eval 'sed 's/foo/foo'" "'bar/g' filename'
Because of the way single quotes don't nest, it is equivalent to:
eval 'sed s/foo/foo" "bar/g filename'
Revised question
Possible solution:
egrep '/.*/' filename | sh
This feeds what is in filename directly to the shell for interpretation. Given file containing:
Some text containing foo; and bar.
More foo bar?
More text; more foo and bar; more foo bar beyond the possibility of unfooing.
The output is:
Some text containing foo bar; and bar.
More foo bar bar?
More text; more foo bar and bar; more foo bar bar beyond the possibility of unfoo baring.
Fixing quotes is hard!
Note that your complex sed script is not complex enough. Given filename containing:
sed 's/foo/foo bar/g' file
sed 's/foo bar/foo bar baz/g' file
the output from:
egrep '/.*/' filename |
sed 's/\(.*\)['"'"']\(.*\) \(.*\)['"'"']\(.*\)/\1'"\'"'\2" "\3'"\'"'\4/g'
is:
sed 's/foo/foo" "bar/g' file
sed 's/foo bar/foo bar" "baz/g' file
which has not solved all the problems for the eval.
I've spent a lot of time, on and off, working on such issues over quite a long period of time (a quarter century is no exaggeration), and it isn't trivial. You can find one discussion in extenso in How to iterate over arguments in bash script. Somewhere, I have another answer which goes through gyrations about this stuff, but I can't immediately find it (where 'immediately' means an hour or so of distracted searching, where the distractions were sets of duplicate questions, etc). It may have been deleted, or I may have looked in the wrong place.
your design is flawed. Create a user interface that doesn't let them input commands directly. give options, or let them enter the parameters only.
At the back end, you do your sanitization check on the parameters before calling sed or other tools desired. You don't have to use eval
Array quoting
The following keeps spaces in arguments by quoting each element of array:
function token_quote {
local quoted=()
for token; do
quoted+=( "$(printf '%q' "$token")" )
done
printf '%s\n' "${quoted[*]}"
}
Example usage:
$ token_quote token 'single token' token
token single\ token token
Above, note the single token's space is quoted as \.
$ set $(token_quote token 'single token' token)
$ eval printf '%s\\n' "$#"
token
single token
token
$
This shows that the tokens are indeed kept separate.
Given some untrusted user input:
% input="Trying to hack you; date"
Construct a command to eval:
% cmd=(echo "User gave:" "$input")
Eval it, with seemingly correct quoting:
% eval "$(echo "${cmd[#]}")"
User gave: Trying to hack you
Thu Sep 27 20:41:31 +07 2018
Note you were hacked. date was executed rather than being printed literally.
Instead with token_quote():
% eval "$(token_quote "${cmd[#]}")"
User gave: Trying to hack you; date
%
eval isn't evil - it's just misunderstood :)
It can actually work as you desire. Use "$#" - this will pass all the arguments exactly as they were given on the command line.
If my_command.sh contains:
sed "$#"
Then my_command.sh 's/foo/foo bar/g' filename will do exactly what you expect.

Do a complete flux of work on bash script

I'm trying to automate a proces which I have to do over and over again in which I have to parse the output from a shell function, look for 5 different things, and then put them on a file
I know I can match patterns with grep however I don't know how to store the result on a variable so I can use it after :(
I also have to parse this very same output to get the other 5 values
I have no idea on how to use the same output for the 5 grep's i need to do and then store it to 5 different variables for after use
I know i have to create a nice and tidy .sh but I don't know how to do this
Currently im trying this
#!/bin/bash
data=$(cat file)
lol=$(echo data|grep red)
echo $lol
not working , any ideas?
you should show some examples of what you want to do next time..
assuming you shell function is called func1
func1(){
echo "things i want to get are here"
}
func1 | grep -E "things|want|are|here|get" > outputfile.txt
Update:
your code
#!/bin/bash
data=$(cat file)
lol=$(echo data|grep red)
echo $lol
practically just means this
lol=$(grep "red" file)
or
lol=$(awk '/red/' file)
also, if you are considering using bash, this is one way you can do it
while read -r myline
do
case "$myline" in
*"red"* ) echo "$myline" >> output.txt
esac
done <file
You can use the following syntax:
VAR=$(grep foo bar)
or alternatively:
VAR=`grep foo bar`
The easiest thing to do would be to redirect the output of the function to a file. You can then run multiple greps on it and only delete the file once you are done with it.
To save the output, you want to use command substitution. This runs a command and then converts the output into command line parameter. Combined with variable assignment you get:
variable=$(grep expression file)
Your second line is wrong. Change it to this:
lol=$(echo "$data"|grep red)
use egrep istead of grep.
variable=$(egrep "exp1|exp2|exp3|exp4|exp5" file)

Resources