BASH automatically adding quotes to string - linux

I'm trying to write a simple bash script that executes a command with one string variable. Upon execution bash adds single quotes to the string variable making the command useless. How do I execute the command without the quotes from the bash script?
#!/bin/bash
key=$(echo $1 | tr '[:lower:]' '[:upper:]')
sudo tee /proc/acpi/bbswitch \<\<\<$key
the output I get is
~/scripts$ bash -x nvidia on
++ echo on
++ tr '[:lower:]' '[:upper:]'
+ key=ON
+ sudo tee /proc/acpi/bbswitch '<<<ON'
the two commands I want to run without the quotes are either
sudo tee /proc/acpi/bbswitch <<<ON
or
sudo tee /proc/acpi/bbswitch <<<OFF

The problem isn't the quotes, it's that sudo doesn't execute the command via the shell. So metacharacters like <<< don't have any special meaning when they're given as sudo arguments. You need to invoke the shell explicitly:
sudo bash -c "tee /proc/acpi/bbswitch <<<$key"
But there doesn't really seem to be a need to use a here-string for this. Just use:
echo "$key" | sudo tee /proc/acpi/bbswitch

There's no need to quote the <<< operator. sudo doesn't read from its standard input by default; it passes it through to the command it runs.
sudo tee /proc/acpi/bbswitch <<< $key

Related

"echo password | sudo -S" with exclamation mark

What I want to do is
$ echo password!p | sudo -S [command]
in a linux terminal (in my case, ubuntu20.04). If you type it as it is, the exclamation mark will refer to the history of the command line, and if !p=pwd, it will be a string like passwordpwd and will not send the password!p correctly. I have tried every way I could find to escape the exclamation, like 'password!p', 'password!p', '\''password!p'\'', etc. The last one behaves the same as 'echo |' but did not result in using the command. Is there any way to get through this?
Could try turning off history expansion.
set +o histexpand
echo -n "password!p" | sudo -S command
set -o histexpand # if you want to restore the capability after

How to deal with multiple quotes in one line bash command?

For example, if my goal is that run a one-line bash command like this,
sudo bash -c ' sudo bash -c '' sudo bash -c ''' echo ''''1234'''' ''' '' '
It doesn't work.
Also I tried the 2nd commnad,
sudo bash -c ' sudo bash -c " sudo bash -c ''' echo ""1234"" ''' " '
Not work neither.
sudo bash -c ' sudo bash -c " echo '''123''' " '
the 3rd one, it indeed works, but it only has 3 levels at the top.
So, is there an actual way to get this command work with only quotes trick?
How to deal with multiple quotes in one line bash command?
Use functions, declare -f and printf "%q" to properly quote stuff. Don't do it yourself.
# Function to run, just normally write stuff to execute.
work() {
echo "1234"
}
# Script to run - contains work function definition and calls work.
script="$(declare -f work); work"
# bash -c "$script"
# quote it
script2="$(printf " %q" bash -c "$script")"
# bash -c "$script2"
# Well, no point, but an example, quote it again:
script3="$(printf " %q" bash -c "$script2")"
bash -c "$script3"
printf "%q " bash -c "$script3"
outputs:
1234
bash -c \ bash\ -c\ \\\ bash\\\ -c\\\ \\\$\\\'work\\\ \\\(\\\)\\\ \\\\n\\\{\\\ \\\\n\\\ \\\ \\\ \\\ echo\\\ \\\"1234\\\"\\\\n\\\}\\\;\\\ work\\\'
You can copy the bash -c .... line to your terminal and execute it.
If you want different quotation style, you can use bash special ${var#Q} variable expansion or /bin/printf executable from coreutils.
Is there an actual way to get this command work with only quotes trick?
No. Quotes are grouped in pars, writing multiple quotes is useless and used for readability. In your example 'bash -c ''''1234''''' is just 'qouted stuff'unqouted stuff'quoted stuff'unqouted stuff' etc... Doing '''' changes nothing. You have to escape \' quotes to preserve literal meaning of them.

How do i make my bash script on download automatically turn into a terminal command? [duplicate]

Say I have a file at the URL http://mywebsite.example/myscript.txt that contains a script:
#!/bin/bash
echo "Hello, world!"
read -p "What is your name? " name
echo "Hello, ${name}!"
And I'd like to run this script without first saving it to a file. How do I do this?
Now, I've seen the syntax:
bash < <(curl -s http://mywebsite.example/myscript.txt)
But this doesn't seem to work like it would if I saved to a file and then executed. For example readline doesn't work, and the output is just:
$ bash < <(curl -s http://mywebsite.example/myscript.txt)
Hello, world!
Similarly, I've tried:
curl -s http://mywebsite.example/myscript.txt | bash -s --
With the same results.
Originally I had a solution like:
timestamp=`date +%Y%m%d%H%M%S`
curl -s http://mywebsite.example/myscript.txt -o /tmp/.myscript.${timestamp}.tmp
bash /tmp/.myscript.${timestamp}.tmp
rm -f /tmp/.myscript.${timestamp}.tmp
But this seems sloppy, and I'd like a more elegant solution.
I'm aware of the security issues regarding running a shell script from a URL, but let's ignore all of that for right now.
source <(curl -s http://mywebsite.example/myscript.txt)
ought to do it. Alternately, leave off the initial redirection on yours, which is redirecting standard input; bash takes a filename to execute just fine without redirection, and <(command) syntax provides a path.
bash <(curl -s http://mywebsite.example/myscript.txt)
It may be clearer if you look at the output of echo <(cat /dev/null)
This is the way to execute remote script with passing to it some arguments (arg1 arg2):
curl -s http://server/path/script.sh | bash /dev/stdin arg1 arg2
For bash, Bourne shell and fish:
curl -s http://server/path/script.sh | bash -s arg1 arg2
Flag "-s" makes shell read from stdin.
Use:
curl -s -L URL_TO_SCRIPT_HERE | bash
For example:
curl -s -L http://bitly/10hA8iC | bash
Using wget, which is usually part of default system installation:
bash <(wget -qO- http://mywebsite.example/myscript.txt)
You can also do this:
wget -O - https://raw.github.com/luismartingil/commands/master/101_remote2local_wireshark.sh | bash
The best way to do it is
curl http://domain/path/to/script.sh | bash -s arg1 arg2
which is a slight change of answer by #user77115
You can use curl and send it to bash like this:
bash <(curl -s http://mywebsite.example/myscript.txt)
I often using the following is enough
curl -s http://mywebsite.example/myscript.txt | sh
But in a old system( kernel2.4 ), it encounter problems, and do the following can solve it, I tried many others, only the following works
curl -s http://mywebsite.example/myscript.txt -o a.sh && sh a.sh && rm -f a.sh
Examples
$ curl -s someurl | sh
Starting to insert crontab
sh: _name}.sh: command not found
sh: line 208: syntax error near unexpected token `then'
sh: line 208: ` -eq 0 ]]; then'
$
The problem may cause by network slow, or bash version too old that can't handle network slow gracefully
However, the following solves the problem
$ curl -s someurl -o a.sh && sh a.sh && rm -f a.sh
Starting to insert crontab
Insert crontab entry is ok.
Insert crontab is done.
okay
$
Also:
curl -sL https://.... | sudo bash -
Just combining amra and user77115's answers:
wget -qO- https://raw.githubusercontent.com/lingtalfi/TheScientist/master/_bb_autoload/bbstart.sh | bash -s -- -v -v
It executes the bbstart.sh distant script passing it the -v -v options.
Is some unattended scripts I use the following command:
sh -c "$(curl -fsSL <URL>)"
I recommend to avoid executing scripts directly from URLs. You should be sure the URL is safe and check the content of the script before executing, you can use a SHA256 checksum to validate the file before executing.
instead of executing the script directly, first download it and then execute
SOURCE='https://gist.githubusercontent.com/cci-emciftci/123123/raw/123123/sample.sh'
curl $SOURCE -o ./my_sample.sh
chmod +x my_sample.sh
./my_sample.sh
This way is good and conventional:
17:04:59#itqx|~
qx>source <(curl -Ls http://192.168.80.154/cent74/just4Test) Lord Jesus Loves YOU
Remote script test...
Param size: 4
---------
17:19:31#node7|/var/www/html/cent74
arch>cat just4Test
echo Remote script test...
echo Param size: $#
If you want the script run using the current shell, regardless of what it is, use:
${SHELL:-sh} -c "$(wget -qO - http://mywebsite.example/myscript.txt)"
if you have wget, or:
${SHELL:-sh} -c "$(curl -Ls http://mywebsite.example/myscript.txt)"
if you have curl.
This command will still work if the script is interactive, i.e., it asks the user for input.
Note: OpenWRT has a wget clone but not curl, by default.
bash | curl http://your.url.here/script.txt
actual example:
juan#juan-MS-7808:~$ bash | curl https://raw.githubusercontent.com/JPHACKER2k18/markwe/master/testapp.sh
Oh, wow im alive
juan#juan-MS-7808:~$

How can I feed input within bash [Executed through the Network]

As the title says, within linux how can I feed input to the bash when I do sudo bash
Lets say I have a bash script that reads the name.
The way I execute the script is through sudo using:
cat read-my-name-script.sh | sudo bash
Lets just say this is how I execute the script throught the network.
Now I want to fill the name automatically, is there a way to feed the input. I tried doing this: cat read-my-name-script.sh < name-input-file | sudo bash where the name-input-file is a file for the input that the user will be using to feed the script.
I am new to linux and learning to automate the input and wanted to create a file for input where the user can fill it and feed it to my script.
This is convoluted, but might do what you want.
sudo bash -c "$(cat read-my-name.sh)" <name-input-file
The -c says the next quoted argument are the commands to run (so, read the script as a string on the command line, instead of from a file), and the calling shell interpolates the contents of the file inside the double quotes before the sudo command gets evaluated. So if read-my-name.sh contains
#!/bin/bash
read -p "I want your name please"
then the command gets expanded into
sudo bash -c '#!/bin/bash
read -p "I want your name please"' <name-input-file
(where of course at this time the shell has actually removed the outer double quotes altogether; I put in single quotes in their place instead to show how this would look as actually executable, syntactically valid code).
I think you need that:
while read -r arg; do sudo bash read-my-name-script.sh "$arg";done <name-input-file
So each line of name-input-file will be passed as argument to sudo bash read-my-name-script.sh
If your argslist located on http server, you can do that:
while read -r arg; do sudo bash read-my-name-script.sh "$arg";done < <(wget -q -O- http://some/address/in/internet/name-input-file)
UPD
add [[ -f name-input-file ]] && readarray -t args <name-input-file
to read-my-name-script.sh
and use "${args[#]}" as arguments of command in the script.
For example echo "${args[#]}" or cmd "${args[0]}" "${args[1]}" ... "${args[100]}" in any order.
In this case you can use
wget -q -O- http://some/address/in/internet/read-my-name-script.sh | bash
for run your script with arguments from name-input-file whitout saving script to the local machine

Problems with fish shell and ssh remote commands

I use fish shell on my desktop.
We use many servers running nginx within docker. I've tried to create a function so I can ssh to the servers and then log into the docker.
The problem is fish is complaining about the $ in the command, but the command is the one to be executed on the remote server (running bash), not on my machine running fish. I've simplified the script to make it easier to see.
config.fish snippet
function ssh-docker-nginx
ssh -t sysadmin#10.10.10.10 "sudo bash && docker exec -it $(docker ps | grep -i nginx | awk '{print $1}') bash"
end
Fish error:
$(...) is not supported. In fish, please use '(docker)'.
~/.config/fish/config.fish (line 59): ssh -t sysadmin#10.10.10.10 "sudo bash && docker exec -it $(docker ps | grep -i nginx | awk '{print $1}') bash"
^
from sourcing file ~/.config/fish/config.fish
called during startup
Is there a way to get fish to ignore this?
You'll want to single-quote that argument.
In double-quotes (") fish will try to expand everything that starts with a $, so it will see that $( and then print the error for it. But it will also see the $1 in your arguments to awk and expand that.
And when you want single-quotes to go to the called command (like here, where you want the argument to awk to be single-quoted because this'll go through bash's expansion), you need to escape the quotes with \.
Try
ssh -t sysadmin#10.10.10.10 'sudo bash && docker exec -it $(docker ps | grep -i nginx | awk \'{print $1}\') bash'
Thanks for the great advice and tip above about the single/double quotes. Unfortunately the escaped quotes in awk did not play nicely being passed to ssh.
After various options, I settled with this approach (which needed force tty):
function ssh-docker-nginx
cat docker-bash.sh | ssh -t -t sysadmin#10.10.10.10
end
# docker-bash.sh
#!/bin/bash
sudo chmod 777 /var/run/docker.sock
sudo docker exec -it $(docker ps | grep -i nginx | awk '{print $1}') bash

Resources