How can I escape double quotes to run this code block on the command line? The part of the code that is problematic is paste('! LaTeX Error: File', paste0("`", x, "'.sty'"), 'not found.')).
Rscript \
-e "biosketch_pkgs <- list('microtype', 'tabu', 'ulem', 'enumitem', 'titlesec')" \
-e "lapply(biosketch_pkgs, function (x) {tinytex::parse_install(text=paste('! LaTeX Error: File', paste0("`", x, "'.sty'"), 'not found.'))})"
I have tried to escape the double quote using the below but it returns unexpected EOF while looking for matching ''`
Rscript \
-e "biosketch_pkgs <- list('microtype', 'tabu', 'ulem', 'enumitem', 'titlesec')" \
-e "lapply(biosketch_pkgs, function (x) {tinytex::parse_install(text=paste('! LaTeX Error: File', paste0("\`"\, x, "\'.sty'"\), 'not found.'))})"
Instead of worrying about how to escape specific strings, think about handling in them a way that avoids the need to do any escaping at all. Running Rscript - tells Rscript to read the source code to run on stdin, while <<'EOF' makes all content up to the next line containing only EOF be fed on stdin. (You can replace the characters EOF with any other sigil you choose, but it's important that this sigil be quoted or escaped to instruct the shell not to modify the content in any way).
Rscript - <<'EOF'
biosketch_pkgs <- list('microtype', 'tabu', 'ulem', 'enumitem', 'titlesec')
lapply(biosketch_pkgs, function (x) {
tinytex::parse_install(text=paste('! LaTeX Error: File',
paste0("`", x, "'.sty'"),
'not found.'))
})
EOF
If you did have a compelling reason to use Rscript -e, though, a correct escaping would put backslashes before backticks, double quotes, or other syntax that has meaning to the shell within a double-quoted string, as follows:
Rscript \
-e "biosketch_pkgs <- list('microtype', 'tabu', 'ulem', 'enumitem', 'titlesec')" \
-e "lapply(biosketch_pkgs, function (x) {tinytex::parse_install(text=paste('! LaTeX Error: File', paste0(\"\`\", x, \"'.sty'\"), 'not found.'))})"
Related
I have a shell script which is trying to trim a file from end of the line but I always get some error.
Shell Script:
AWK_EXPRESSION='{if(length>'"$RANGE1"'){ print substr('"$0 "',0, length-'"$RANGE2"'}) } else { print '"$0 "'} }'
for report in ${ACTUAL_TARGET_FOLDER}/* ; do
awk $AWK_EXPRESSION $report > $target_file
done
If I trigger the AWK command, I get unexpected newline or end of string near print.
What am I missing?
Why are you trying to store the awk body in a shell variable? Just use awk and the -v option to pass a shell value into an awk variable:
awk -v range1="$RANGE1" -v range2="$RANGE2" '{
if (length > range1) {
print substr($0,0, length-range2)
} else {
print
}
}' "$ACTUAL_TARGET_FOLDER"/* > "$target_file"
Add a few newlines to help readability.
Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.
Unquoted variables are subject to word splitting and glob expansion. Use double quotes for all your variables unless you know what specific side-effect you want to use.
I would recommend writing the AWK program using AWK variables instead of interpolating variables into it from the shell. You can pass variable into awk on the command line using the -v command line option.
Also, awk permits using white space to make the program readable, just like other programming languages. Like this:
AWK_EXPRESSION='{
if (length > RANGE1) {
print substr($0, 1, length-RANGE2)
} else {
print
}
}'
for report in "${ACTUAL_TARGET_FOLDER}"/* ; do
awk -v RANGE1="$RANGE1" -v RANGE2="$RANGE2" "$AWK_EXPRESSION" "$report" > "$target_file"
done
I have several shell commands that I want to run in in R.
I have tried system() but I have not find out how to do the right escaping even using shQuote.
# works OK
system('ls -a -l')
but how I execute a command like perl -e 'print "test\n"' or curl --data-urlencode query#biomart.xml http://biomart.org/biomart/martservice/results inside R?
update:
In the case of commands like the perl example I do not know how to do the escaping of quotes as it needs to be quoted as string but already use both types of quotes.
In the case of curl, the problem seems to be in the RESTful call to pass the xml with the # that works in the shell but not in the system() call
dat <-system('curl --data-urlencode query#biomart.xml http://biomart.org/biomart/martservice/results', intern=F)
Warning: Couldn't read data from file "query#biomart.xml", this makes an empty
Warning: POST.
The file is biomart.xml not query#biomart.xml
** Update2**
The xml file I am using for test is:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Query>
<Query virtualSchemaName = "default" formatter = "TSV" header = "0" uniqueRows = "0" count = "" datasetConfigVersion = "0.6" >
<Dataset name = "hsapiens_gene_ensembl" interface = "default" >
<Filter name = "hgnc_symbol" value = "LDLR"/>
<Attribute name = "external_gene_id" />
</Dataset>
</Query>
Strings in R may be enclosed in either single (') or double (") quotes.
If you want to execute a command with both single and double quotes, such as:
perl -e 'print "test\n"'
then it is of little consequence which you choose for your R string - since one pair needs to be escaped either way.
Let's say you choose single quotes:
system('')
Then we need to escape the single quotes in the same way as for the newline character, with the escape character, \:
command <- 'perl -e \'print "test\n"\''
system(command)
It is also possible to encode Unicode characters in this way with \Unnnnnnnn or \unnnn. Alternatively with octal (\nnn), or hex (\xnnn).
Thus:
atSymbol <- '\u0040' # '\x040' '\100'
If the # in your curl command is causing the problem, encoding it like this should fix it.
In this example, in addition to escaping ', I had to escape \\ (with \\\\), \., \G, \K, but not \n
⌄ ⌄⌄ ⌄ ⌄ ⌄ ⌄ ⌄ ⌄
perl -0777 -pi -e ' s{ \\usage.*?\n\.\.\.\n} { ($r = $&) =~ s/\n//g; $r =~ s/\G.{0,79}(,|.$)\K/\n/g; $r }gse' filename.txt
system('perl -0777 -pi -e \' s{\\\\usage.*?\n\\.\\.\\.\n}{ ($r = $&) =~ s/\n//g; $r =~ s/\\G.{0,79}(,|.$)\\K/\n/g; $r }gse\' filename.txt')
i want to set the value of inputLineNumber to 20. I tried checking if no value is given by user by [[-z "$inputLineNumber"]] and then setting the value by inputLineNumber=20. The code gives this message ./t.sh: [-z: not found as message on the console. How to resolve this? Here's my full script as well.
#!/bin/sh
cat /dev/null>copy.txt
echo "Please enter the sentence you want to search:"
read "inputVar"
echo "Please enter the name of the file in which you want to search:"
read "inputFileName"
echo "Please enter the number of lines you want to copy:"
read "inputLineNumber"
[[-z "$inputLineNumber"]] || inputLineNumber=20
for N in `grep -n $inputVar $inputFileName | cut -d ":" -f1`
do
LIMIT=`expr $N + $inputLineNumber`
sed -n $N,${LIMIT}p $inputFileName >> copy.txt
echo "-----------------------" >> copy.txt
done
cat copy.txt
Changed the script after suggestion from #Kevin. Now the error message ./t.sh: syntax error at line 11: `$' unexpected
#!/bin/sh
truncate copy.txt
echo "Please enter the sentence you want to search:"
read inputVar
echo "Please enter the name of the file in which you want to search:"
read inputFileName
echo Please enter the number of lines you want to copy:
read inputLineNumber
[ -z "$inputLineNumber" ] || inputLineNumber=20
for N in $(grep -n $inputVar $inputFileName | cut -d ":" -f1)
do
LIMIT=$((N+inputLineNumber))
sed -n $N,${LIMIT}p $inputFileName >> copy.txt
echo "-----------------------" >> copy.txt
done
cat copy.txt
Try changing this line from:
[[-z "$inputLineNumber"]] || inputLineNumber=20
To this:
if [[ -z "$inputLineNumber" ]]; then
inputLineNumber=20
fi
Hope this helps.
Where to start...
You are running as /bin/sh but trying to use [[. [[ is a bash command that sh does not recognize. Either change the shebang to /bin/bash (preferred) or use [ instead.
You do not have a space between [[-z. That causes bash to read it as a command named [[-z, which clearly doesn't exist. You need [[ -z $inputLineNumber ]] (note the space at the end too). Quoting within [[ doesn't matter, but if you change to [ (see above), you will need to keep the quotes.
Your code says [[-z but your error says [-z. Pick one.
Use $(...) instead of `...`. The backticks are deprecated, and $() handles quoting appropriately.
You don't need to cat /dev/null >copy.txt, certainly not twice without writing to it in-between. Use truncate copy.txt or just plain >copy.txt.
You seem to have inconsistent quoting. Quote or escape (\x) anything with special characters (~, `, !, #, $, &, *, ^, (), [], \, <, >, ?, ', ", ;) or whitespace and any variable that could have whitespace. You don't need to quote string literals with no special characters (e.g. ":").
Instead of LIMIT=`expr...`, use limit=$((N+inputLineNumber)).
I have a script that has a string in a file name like so:
filename_with_spaces="a file with spaces"
echo test > "$filename_with_spaces"
test_expect_success "test1: filename with spaces" "
run cat \"$filename_with_spaces\"
run grep test \"$filename_with_spaces\"
"
test_expect_success is defined as:
test_expect_success () {
echo "expecting success: $1"
eval "$2"
}
and run is defined as:
#!/bin/zsh
# make nice filename removing special characters, replace space with _
filename=`echo $# | tr ' ' _ | tr -cd 'a-zA-Z0-9_.'`.run
echo "#!/bin/zsh" > $filename
print "$#" >> $filename
chmod +x $filename
./$filename
But when I run the toplevel script test_expect_success... I get cat_a_file_with_spaces.run with:
#!/bin/zsh
cat a file with spaces
The problem is the quotes around a file with spaces in cat_a_file_with_spaces.run is missing. How do you get Z shell to keep the correct quoting?
Thanks
Try
run cat ${(q)filename_with_spaces}
. It is what (q) modifier was written for. Same for run script:
echo -E ${(q)#} >> $filename
. And it is not bash, you don't need to put quotes around variables: unless you specify some option (don't remember which exactly)
command $var
always passes exactly one argument to command no matter what is in $var. To ensure that some zsh option will not alter the behavior, put
emulate -L zsh
at the top of every script.
Note that initial variant (run cat \"$filename_with_spaces\") is not a correct quoting: filename may contain any character except NULL and / used for separating directories. ${(q)} takes care about it.
Update: I would have written test_expect_success function in the following fashion:
function test_expect_success()
{
emulate -L zsh
echo "Expecting success: $1" ; shift
$#
}
Usage:
test_expect_success "Message" run cat $filename_with_spaces
The following shell script takes a list of arguments, turns Unix paths into WINE/Windows paths and invokes the given executable under WINE.
#! /bin/sh
if [ "${1+set}" != "set" ]
then
echo "Usage; winewrap EXEC [ARGS...]"
exit 1
fi
EXEC="$1"
shift
ARGS=""
for p in "$#";
do
if [ -e "$p" ]
then
p=$(winepath -w $p)
fi
ARGS="$ARGS '$p'"
done
CMD="wine '$EXEC' $ARGS"
echo $CMD
$CMD
However, there's something wrong with the quotation of command-line arguments.
$ winewrap '/home/chris/.wine/drive_c/Program Files/Microsoft Research/Z3-1.3.6/bin/z3.exe' -smt /tmp/smtlib3cee8b.smt
Executing: wine '/home/chris/.wine/drive_c/Program Files/Microsoft Research/Z3-1.3.6/bin/z3.exe' '-smt' 'Z: mp\smtlib3cee8b.smt'
wine: cannot find ''/home/chris/.wine/drive_c/Program'
Note that:
The path to the executable is being chopped off at the first space, even though it is single-quoted.
The literal "\t" in the last path is being transformed into a tab character.
Obviously, the quotations aren't being parsed the way I intended by the shell. How can I avoid these errors?
EDIT: The "\t" is being expanded through two levels of indirection: first, "$p" (and/or "$ARGS") is being expanded into Z:\tmp\smtlib3cee8b.smt; then, \t is being expanded into the tab character. This is (seemingly) equivalent to
Y='y\ty'
Z="z${Y}z"
echo $Z
which yields
zy\tyz
and not
zy yz
UPDATE: eval "$CMD" does the trick. The "\t" problem seems to be echo's fault: "If the first operand is -n, or if any of the operands contain a backslash ( '\' ) character, the results are implementation-defined." (POSIX specification of echo)
bash’s arrays are unportable but the only sane way to handle argument lists in shell
The number of arguments is in ${#}
Bad stuff will happen with your script if there are filenames starting with a dash in the current directory
If the last line of your script just runs a program, and there are no traps on exit, you should exec it
With that in mind
#! /bin/bash
# push ARRAY arg1 arg2 ...
# adds arg1, arg2, ... to the end of ARRAY
function push() {
local ARRAY_NAME="${1}"
shift
for ARG in "${#}"; do
eval "${ARRAY_NAME}[\${#${ARRAY_NAME}[#]}]=\${ARG}"
done
}
PROG="$(basename -- "${0}")"
if (( ${#} < 1 )); then
# Error messages should state the program name and go to stderr
echo "${PROG}: Usage: winewrap EXEC [ARGS...]" 1>&2
exit 1
fi
EXEC=("${1}")
shift
for p in "${#}"; do
if [ -e "${p}" ]; then
p="$(winepath -w -- "${p}")"
fi
push EXEC "${p}"
done
exec "${EXEC[#]}"
I you do want to have the assignment to CMD you should use
eval $CMD
instead of just $CMD in the last line of your script. This should solve your problem with spaces in the paths, I don't know what to do about the "\t" problem.
replace the last line from $CMD to just
wine '$EXEC' $ARGS
You'll note that the error is ''/home/chris/.wine/drive_c/Program' and not '/home/chris/.wine/drive_c/Program'
The single quotes are not being interpolated properly, and the string is being split by spaces.
You can try preceeding the spaces with \ like so:
/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe
You can also do the same with your \t problem - replace it with \\t.