build bash string containing a variable value surrounded with single quotes - string

I'm having a nightmare from what should be the most trivial of tasks.
My final goal is issue the following command from a bash script:
sqlite3 my_db.db '.read my_file.sql'
There are two catches here:
1. The single-quotes are obligatory, and can't be replaced by, say, double-quotes
2. my_file.sql is a variable known only at run-time.
So what I need is a way to have bash build a string that on one hand contains a variable value, while on the other hand that value should be surrounded by single quotes.
I would also much prefer a solution not relying on additional tools like AWK, Perl or the like. Maybe sed if it's really necessary.
Thanks.
Thanks Jonathan and Nelson.
I tried all three suggestions, but they all failed.
For simplicity I reduced the problem to the following:
I wrote the following script (tst.sh):
#!/bin/bash
file=/tmp/1
ls "'"$file"'"
ls \'$file\'
ls "'$file'"
Then I isuues the following commands:
$ touch /tmp/1
$ ls '/tmp/1'
/tmp/1
$ ./tst.sh
'/tmp/1': No such file or directory
'/tmp/1': No such file or directory
'/tmp/1': No such file or directory
It seems the quotes were indeed added, but the resulting command was not the same as when entered manually.
Any ideas ?

Single-quotes are not obligatory. All of the following commands run sqlite3 with exactly the same arguments:
sqlite3 my_db.db '.read my_file.sql'
sqlite3 my_db.db ".read my_file.sql"
sqlite3 my_db.db .read\ my_file.sql
sqlfile="my_file.sql"
sqlite3 my_db.db ".read $sqlfile"
In all cases, the quotes (/escape) are parsed and removed before the arguments are passed to sqlite3. This is what you want. You want sqlite3 to get two arguments: my_db.db and .read my_file.sql. You do not want sqlite3 to see the quotes around the command -- that would be the equivalent of:
$ sqlite3 my_db.db
SQLite version 3.7.7 2011-06-25 16:35:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> '.read my_file.sql'
...>
...which, as you can see, just confuses sqlite3.
BTW, this is the same as the problem in your ls examples: you're passing single-quotes as part of the argument to ls, so it's looking for a file with single-quotes in the name and not finding it. You want the shell to remove the quotes rather than pass them to the command as part of an argument.

This will do what you say you want to do (getting single quotes to the program), but it uses double quotes:
sqlite3 my_db.db "'".read" "my_file.sql"'"
Avoiding double quotes, you can write:
sqlite3 my_db.db \'.read\ my_file.sql\'
For both of these, the second argument will be seen by sqlite3 as a string containing:
'.read my_file.sql'
If the file name is in a variable (file=my_file.sql), then:
sqlite3 my_db.db "'".read" "$file"'"
sqlite3 my_db.db \'.read\ $file\'
These notations are vulnerable to confusion if the file name contains spaces.
However, I don't think that's likely to be what you really want. The proscription on double quotes is puzzling, and the requirement for single quotes is likewise puzzling.

You can do as follows:
VAR=my_file.sql
VAR2="'.read $VAR'"
sqlite3 my_db.db $VAR2

user1860085, if you check out documentation for sqlite3 command and you will know how shell treats quotes and white spaces, you will probably come to conclusion that you want double quotes for your case.
but if you really want single quotes, here is solution:
eval sqlite3 my_db.db \'.read $VARIABLE\'
which in the fly will change to:
sqlite3 my_db.db '.read my_file.sql'
But I don't see why you could want it...

OK, problem solved !!
All that was missing is adding a little 'eval' command before the line.
So, in the simple example script I gave, changing:
ls "'$file'" to:
eval ls "'$file'"
did the job.
Thanks to all replyers :-)

Related

How do I pass ">>" or "<<" to my script without the terminal trying to interpret it as me either appending to something or getting stdin?

My python script can take a series of bitwise operators as one of its arguments. They all work fine except for "=<<" which is roll left, and "=>>" which is roll right. I run my script like ./script.py -b +4,-4,=>>10,=<<1, where anything after -b can be any combination of similar operations. As soon as the terminal sees "<<" though, it just drops the cursor to a new line after the command and asks for more input instead of running the script. When it sees ">>", my script doesn't process the arguments correctly. I know it's because bash uses these characters for a specific purpose, but I'd like to get around it while still using "=>>" and "=<<" in my arguments for my script. Is there any way to do it without enclosing the argument in quotation marks?
Thank you for your help.
You should enclose the parameters that contain special symbols into single quotation marks (here, echo represents your script):
> echo '+4,-4,=>>10,=<<1'
+4,-4,=>>10,=<<1
Alternatively, save the parameters to a file (say, params.txt) and read them from the file onto the command line using the backticks:
> echo `cat params.txt`
+4,-4,=>>10,=<<1
Lastly, you can escape some offending symbols:
> echo +4,-4,=\>\>10,=\<\<1
+4,-4,=>>10,=<<1

how to specify path with space inside file in linux

cat ~/.last_dir
/mnt/c/Users/Administrator/OneDrive/Desktop/main project/backup/main project 2
cd cat ~/.last_dir
-bash: cd: too many arguments
I tried using backslash inside the file
/mnt/c/Users/Administrator/OneDrive/Desktop/main\ project/backup/main\ project\ 2
Still same error
You need to quote the results of expanding cat ...:
cd "$(cat ~/.last_dir)"
cd "$(<~/.last_dir)"
First, put quotes around the $(...) to make the space part of the filename.
Second, $(<...) is a bash construct that reads the file directly without executing cat, but is not entirely portable.
For a more generic, less bash-specific version, use Maxim's solution.
just put quotation marks around your path:
"/mnt/c/Users/Administrator/OneDrive/Desktop/main project/backup/main project 2"
this should work for most cases

bash handling of quotation marks in filename

I am trying to remove and replace quotation marks that are present in a file name. For example, I would like to change:
$ ls
abc"def"ghi"jkl"mno
to this
$ ls
abc:def:ghi:jkl:mno
In trying to solve this, I came across How to rename a bunch of files to eliminate quote marks, which is exactly what I want to do. However, it didn't work for my case. To figure out why, I tried creating a test file like this:
$ touch abba\"abba\"cde\"cde\"efef
With this file, the solutions I came across (such as mentioned above) worked. But why didn't it work for the first file?
One thing I discovered was that bash command completion sees them differently. If I type in
$ ls abb<tab>
bash will complete the filename like so:
$ abba\"abba\"cde\"cde\"efef
just as I created it. But for the original file, bash completion went like this:
$ ls abc<tab>
results in
$ abc"def"ghi"jkl"mno
So in the test case file, there is an escape of the quotation marks, and in the other case (the file I really want to rename), there is no escaping of the the quotation marks. I don't know how the original files were named.
Can anyone explain why bash sees these names differently, and how I would go about renaming my file?
Here is two ways to rename a file with "(quotation) mark,
option 1: With escape character \
mv abc\"cdf\"efg\"hij newFileName
option 2: By using '(single quote)
mv 'abc"cdf"efg"hij' newFileName
Note: using special charaters like :(colon) in file name might not be a good idea,
and regarding the auto completion, it usually fill the name with escape character, example
ls abc<tab> will complete the name to ls abc\"cdf\"efg\"hij
unless you start the name with a quote, example
ls 'abc<tab> will complete the name to ls 'abc"cdf"efg"hij'

Concatinating paths in bash (.sh) resolves in path with '$'\r''

I get a string from a command that lokos like the following:
part1=$(pip install numpy 2>&1)
part1 has stored some variable like: c:\programdata\anaconda3\lib\site-package
Now I want to append "numpy" to it. To do so I tried it with:
part1+=/numpy
and every other solution listed here:
How to concatenate strings in bash
However the output looks like this: 'c:\programdata\anaconda3\lib\site-packages'$'\r''/numpy'
What do I have to do to get rid of this effect?
I am using Windows10 and scripting .sh files.
You can use:
part1="${part1/$'\r'}/numpy"
Here "${part1/$'\r'} replaces \r by an empty string. $'\r' is special bash construct to enter escape sequences.

Multiword string as a curl option using Bash

I want to get some data from a HTTP server. What it sends me depends on what I put in a POST request.
What I put in the INPUT_TEXT field is a sequence of words. When I run the following command, I get good looking output.
$ curl http://localhost:59125/process -d INPUT_TEXT="here are some words"
I want a bash script to take some string as a command line argument, and pass it appropriately to curl. The first thing I tried was to put the following in a script:
sentence=$1
command="curl http://localhost:59125/process -d INPUT_TEXT=\"${sentence}\""
$command
I then run the script like so:
$ ./script "here are some words"
But then I get a curl Couldn't resolve host error for each of "are", "some", and "words". It would seem that "here" got correctly treated as the INPUT_TEXT, but the rest of the words were then considered to be hosts, and not part of the option.
So I tried:
command=("curl" "http://localhost:59125/process" "-d" "INPUT_TEXT='$sentence'")
${command[#]}
I got the same output as the first script. I finally got what I wanted with:
result=$(curl http://localhost:59125/process -d INPUT_TEXT="${sentence}")
echo $result
I'm still unsure as to what the distinction is. In the first two cases, when I echoed out the contents of command, I get exactly what I input from the interactive Bash prompt, which had worked fine. What caused the difference?
The following will work:
command=("curl" "http://localhost:59125/process"
"-d" "INPUT_TEXT=$sentence")
"${command[#]}"
That has two changes from yours:
I removed the incorrect quotes around $sentence since you don't want to send quotes to the server (as far as I can see).
I put double-quotes around the use of "${command[#]}". Without the double quotes, the array's elements are concatenated with spaces between them and then the result is word-split. With double quotes, the individual array elements are used as individual words.
The second point is well-explained in the bash FAQ and a bunch of SO answers dealing with quotes.
The important thing to understand is that quotes only quote when a command is parsed. A quote which is a character in a variable is just a character; it is not reinterpreted when the value of the variable expanded. Whitespace in the variable is used for word-splitting if the variable expansion is unquoted; the fact that the whitespace was quoted in the the command which defined the variable is completely irrelevant. In this sense, bash is just the same as any other programming language.

Resources