In a directory which is added to my $PATH I have the following file:
filename="$1" day="$2" month="$3"
ruby -r "./SomeClass.rb" -e 'SomeClass.run($filename, $day, $month)'
Suppose this file is called someclass. When I type someclass into terminal my system recognizes it as a valid command and runs the corresponding Ruby file correctly. But the arguments are not being passed in. How do I pass arguments into an alias?
How do I pass arguments into an alias?
Don't use an alias, better to declare a function for this. You can pass arguments and do other stuff easily inside a bash function:
someclass() {
# make sure enough arguments are passed in
# echo "$1 - $2 - $3";
filename="$1"; day="$2"; month="$3";
ruby -r "./SomeClass.rb" -e "SomeClass.run($filename, $day, $month)";
}
You are using single quote. Change them to double:
ruby -r "./SomeClass.rb" -e "SomeClass.run($filename, $day, $month)"
No expansion are done within single quotes. From bash manual:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
3.1.2.3 Double Quotes
Enclosing characters in double quotes (‘"’) preserves the literal value of all characters within the quotes, with the exception of ‘$’, ‘`’, ‘\’, and, when history expansion is enabled, ‘!’. The characters ‘$’ and ‘`’ retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: ‘$’, ‘`’, ‘"’, ‘\’, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ‘!’ appearing in double quotes is escaped using a backslash. The backslash preceding the ‘!’ is not removed.
A useful page on quotes I am using is on grymoire.
Regarding the title of the question, check this question (Alias with variable in bash) and its answer: you can't and have to use functions.
Related
The problem:
By typing, echo "Hello World!", into the terminal I'm am answered with: dquote>
The Question (2-parts):
If I use single quotes, terminal returns the result that I'm expecting to see: Hello World!
How do you escape an !?
Why are double quotes different than single quotes here?
I have tried:
Using backslash, echo "Hello World/!" doesn't seem to work, I'm still returned dquote>.
I've also tried looking for other answers on escape characters and stackoverflow answers. They usually end up going over my head.
About question 1: (How do you escape an !?)
You can use "'!'"
Example:
echo "Hello World"'!'""'!'" I'm there."
Result:
Hello World!! I'm there.
About question 2: (Why are double quotes different than single quotes here?)
Because ! is the default "history expansion" character and inside double quotes "history expansion" is performed.
Bash manual:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
3.1.2.3 Double Quotes
Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.
The special parameters * and # have special meaning when in double quotes (see Shell Parameter Expansion).
I have this strange issue with my bash script. I compile boost as part of it. The call from the script looks like this:
./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH="${ICU_PREFIX}" -sICU_LINK="${BOOST_ICU_LIBS}" >> "${BOOST_LOG}" 2>&1
That command works perfectly well. The log file shows that it finds ICU without a problem. However, if I change it to run from a variable, it no longer finds ICU (but it still compiles everything else):
bcmd="./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=\"${ICU_PREFIX}\" -sICU_LINK=\"${BOOST_ICU_LIBS}\""
$bcmd >> "${BOOST_LOG}" 2>&1
What's the difference? I would like to be able to use the second approach so that I can pass the command into another function before running it.
Don't use a variable to store complex commands involving quotes that are nested. The problem is when you call the variable with just $cmd, the quotes are stripped incorrectly. Putting commands (or parts of commands) into variables and then getting them back out intact is complicated.
Quote removal is part of the one of the word expansions done by the shell. From the excerpt seen in POSIX specification of shell
2.6.7 Quote Removal
The quote characters ( backslash, single-quote, and double-quote) that were present in the original word shall be removed unless they have themselves been quoted.
Your example can be simply reproduced by a simple example. Assuming you have a few command flags (not actual ones)
cmdFlags='--archive --exclude="foo bar.txt"'
If you carefully look through the above, it contains 2 args, one --archive and another for --exclude="foo bar.txt", notice the double-quotes which needs to be preserved when you are passing it.
Notice how the quotes are incorrectly split when I don't quote cmdFlags, in the printf() call below
printf "'%s' " $cmdFlags; printf '\n'
'--archive' '--exclude="foo' 'bar.txt"'
and compare the result with one with proper quoting done below.
printf "'%s' " "$cmdFlags"; printf '\n'
'--archive --exclude="foo bar.txt"'
So along with the suggestion of properly quoting the variable, the general suggestion would be to use an array to store the flags and pass the quoted array expansion
cmdArray=()
cmdArray=(./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH="${ICU_PREFIX}" -sICU_LINK="${BOOST_ICU_LIBS}")
and pass the array as
"${cmdArrray[#]}" >> "${BOOST_LOG}" 2>&1
Try to use eval when you want to execute a string as a command. This way, you won't have issues regarding strings that have spaces etc. The expanded cmd string is not re-evaluated by bash hence, things like "hi there" are expanded as two separate tokens.
eval "$bcmd" >> "${BOOST_LOG}" 2>&1
To demonstrate this behavior, consider this code:
cmd='echo "hi there"'
$cmd
eval "$cmd"
Which outputs to:
"hi there"
hi there
The token "hi there" is not re-evaluated as a quoted string.
Use single quota instead of two.
bcmd='./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=\"${ICU_PREFIX}\" -sICU_LINK=\"${BOOST_ICU_LIBS}\"'
Bash documentation states that single quota does not interpolate:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
That way you omit double-quota stripping and removing problem, and your string will be passed correctly. If you want to stay with double quotes, you have to vary that they DO NOT preserve literal value of certain characters: $, ' and \ unless preceded with \, as manual states:
3.1.2.3 Double Quotes
Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash.
In your example you forgot to mark $ with backslash as well. Difference between these two is explained perfectly by Adam here: Differences between single and double quota
I am trying to input something on terminal after reading from file. I am using xautomation for this, but I am not sure how to enter a variable in xautomation. PFB my code -
FILENAME="sample.txt"
#set -vx
QUOTES=\'
cat $FILENAME | while read LINE
do
set -vx
# echo $QUOTES$STR$LINE$QUOTES
xte 'sleep 1' \'$LINE\' 'key Return'
#read the output and put in the output text file
done
EDIT: but on terminal it gives output as -
+ read LINE
+ set -vx
+ xte 'sleep 1' ''\''str' 'pwd'\''' 'key Return'
Unknown command ''str'
Unknown command 'pwd''
EDIT2
1 command - xte 'sleep 1' 'str pwd' 'key Return' This will give output of pwd command. so while running any code I need to put quotes around it.
Please let me know if I am doing it wrongly, I am new to shell programming.
thanks
xte 'sleep 1' "${LINE}" 'key Return'
You have to use double quotes to preserve the variable and use the proper format for calling variables in strings.
Quoting the GNU Bash reference:
Enclosing characters in double quotes (‘"’) preserves the literal value of all characters within the quotes, with the exception of ‘$’, ‘’, ‘\’, and, when history expansion is enabled, ‘!’. When the shell is in POSIX mode (see Bash POSIX Mode), the ‘!’ has no special meaning within double quotes, even when history expansion is enabled. The characters ‘$’ and ‘’ retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: ‘$’, ‘`’, ‘"’, ‘\’, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ‘!’ appearing in double quotes is escaped using a backslash. The backslash preceding the ‘!’ is not removed.
I've got this in a for loop in a bash script:
xpath $f '//bad/objdesc/desc[$i]' > $f.$i.xml
$i is the counter.
It doesn't work.
How do I refer to $i properly in the brackets of the desc element?
Thanks.
Use double quotes instead, so that the variable gets expanded instead of being treated literally as $i:
xpath "$f" "//bad/objdesc/desc[$i]" > "$f.$i.xml"
From the bash manual:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
3.1.2.3 Double Quotes
Enclosing characters in double quotes (‘"’) preserves the literal value of all characters within the quotes, with the exception of ‘$’, ‘’, ‘\’, and, when history expansion is enabled, ‘!’. The characters ‘$’ and ‘’ retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: ‘$’, ‘`’, ‘"’, ‘\’, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ‘!’ appearing in double quotes is escaped using a backslash. The backslash preceding the ‘!’ is not removed.
Here's a much more efficient alternate approach, for the specific indexing-into-a-list case.
counter=1
while IFS='' read -r -d $'\x03' line; do
printf '%s' "$line" >"%f.$(( counter++ )).xml"
done < <(xmlstarlet sel -t -m //bad/objdesc/desc -v . -o $'\x03')
This runs xmlstarlet (a more capable alternative to xpath) only once, and retrieves the entire set of values (even should they be multiline) into a bash array, where they can be accessed as ${array[0]}, ${array[1]}, etc.
It has the caveat that values containing the literal EOT character within their contents will be split into multiple values on that character.
A word on safety:
Expanding query parameters -- whether XPath, SQL, or otherwise -- within double quotes in bash opens you up to query injection attacks. Let's say you had a variable with a customer IDs, and you were looking up account balances; if you used xpath "//record[customer='$id' and record='$rec']", a customer who could provide literal values for $rec could also look up content belonging to customers with a different ID by escaping the quotes.
The safe alternative is to use a tool that lets you pass your query in single-quotes, and pass your parameters out-of-band, as with a --var name="$value" parameter. Until it has this capability, I cannot advise the Perl xpath tool for general use.
Should someone other than the original poster of the question be considering using the xpath tool with user-provided or untrusted data, please keep the above in mind.
I want to print double quotes using echo statement in shell programming.
Example:
echo "$1,$2,$3,$4";
prints xyz,123,abc,pqrs
How to print "xyz","123","abc","pqrs";
I had tried to place double quotes in echo statement but its not being printed.
You just have to quote them:
echo "\"$1\",\"$2\",\"$3\",\"$4\""
As noted here:
Enclosing characters in double quotes (‘"’) preserves the literal
value of all characters within the quotes, with the exception of ‘$’,
‘`’, ‘\’, and, when history expansion is enabled, ‘!’. The characters
‘$’ and ‘`’ retain their special meaning within double quotes (see
Shell Expansions). The backslash retains its special meaning only when
followed by one of the following characters: ‘$’, ‘`’, ‘"’, ‘\’, or
newline. Within double quotes, backslashes that are followed by one of
these characters are removed. Backslashes preceding characters without
a special meaning are left unmodified. A double quote may be quoted
within double quotes by preceding it with a backslash. If enabled,
history expansion will be performed unless an ‘!’ appearing in double
quotes is escaped using a backslash. The backslash preceding the ‘!’
is not removed.
The special parameters ‘*’ and ‘#’ have special meaning when in double
quotes (see Shell Parameter Expansion).
Use printf, no escaping is required:
printf '"%s","%s","%s","%s";\n' "$1" "$2" "$3" "$4"
and the trailing ; gets printed too!
You should escape the " to make it visible in the output, you can do this :
echo \""$1"\",\""$2"\",\""$3"\",\""$4"\"