5

I find tilde expansion does not work for the following situation:

$ set -x

$ ./print_arg.pl destdir=~/test
+ ./print_arg.pl 'destdir=/root/test'
destdir=/root/test

$ ./print_arg.pl dest-dir=~/test
+ ./print_arg.pl 'dest-dir=~/test'
dest-dir=~/test

$ ./print_arg.pl -destdir=~/test
+ ./print_arg.pl '-destdir=~/test'
dest-dir=~/test

The contents of print_arg.pl is

#!/usr/bin/perl
print $ARGV[0],"\n";

According to Order of Shell processing, Shell will split word before "tilde expansion". And I noticed that word split are different actually. What is the reason for the different results?

lisper
  • 75
  • 6

1 Answers1

4

Tilde expansion also occurs in shell variable assignment, which destdir=~/test resembles. dest-dir=~/test and -destdir=~/test do not, since - is not a valid character in a variable name. Although the shell is not evaluating destdir=~/test as a variable assignment (it would, if set -k is used), it appears the parser is still treating it as such and performing tilde expansion on the RHS.

From http://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html#Tilde-Expansion:

Each variable assignment is checked for unquoted tilde-prefixes immediately following a ‘:’ or the first ‘=’. In these cases, tilde expansion is also performed. Consequently, one may use file names with tildes in assignments to PATH, MAILPATH, and CDPATH, and the shell assigns the expanded value.

Note that with the -k option set, proper variable assignments are processed as such and removed from the argument list passed to print_arg.pl:

~ $ set -kx
~ $ ./print_arg.pl destdir=~/bin foo
+ destdir=/Users/clint/bin
+ ./print_arg.pl foo
foo
~ $ ./print_arg.pl dest-dir=~/bin foo
+ ./print_arg.pl 'dest-dir=~/bin' foo
dest-dir=~/bin
chepner
  • 389,128
  • 51
  • 403
  • 529
  • I also noticed the sentence "The words that the parser has marked as variable assignments (**those preceding the command name**) and redirections are saved for later processing." So "destdir=~/test" after the command might not be marked as a vaiable assignment. Then how to explain it? – lisper Mar 19 '13 at 16:13
  • Because of the `set -k` shell option, it *could* be a variable assignment. My guess is that the parser doesn't check if that option is set, and marks anything that might be a valid assignment as such. After parsing is completed (including tilde expansion), the code responsible for evaluating the parsed command can check if assignments following a command should be evaluated, according to `set -k`. One could argue that it is a bug in `bash` to ignore `set -k` when first identifying variable assignments. – chepner Mar 19 '13 at 16:16
  • 1
    I get it. Thank you for the very great explanation. – lisper Mar 19 '13 at 16:25
  • This also can affect patterns like `mycmd --longopt=~/some/path`. To use tilde expansion, you can usually omit the '=' if the long option format for your command supports it: `mycmd --longopt ~/some/path`. Otherwise, you have to manually expand it in a subshell: `mycmd --longopt=$(expr ~/some/path)` – TrinitronX May 14 '13 at 16:28