If the author was trying to catch you out by talking about that literal string (without shell expansion) as a path, then it's a relative path (mkdir -p './~/Documents'
). Otherwise:
It's an absolute path, because resolving it doesn't depend on the process's current working directory. Relative path always means relative to the process's working directory. Or in the case of symlink targets, relative to the location of the symlink. (gcc -> gcc-5.2
vs. gcc -> /usr/bin/gcc-5.2
). This matters for NFS-mounts and other cases where you can get to the same symlink via different absolute paths. e.g.
/net/tesla/home/peter/foo -> bar # always works from other machines
/net/tesla/home/peter/foo -> /home/peter/bar # references my home dir on the local machine, not tesla.
Debian will sometimes install symlinks to ../../doc/whatever/whatever
, instead of an absolute symlink target, so it works when NFS mounted somewhere else, or when looking at a chroot without chroot(8)
ing into it.
Every Unix process has its own cwd. The pwd
command exists just to print it.
see: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html
for more about changing directories with POSIX system calls.
As everyone else has said, ~
is expanded by the shell before the path is used for anything. Using ~/bin/myprog
in a shell script will make it work differently for different users. The difference between ~/bin/foo
and /home/peter/bin/foo
is that one of them has hard-coded the location, while the other has parameterized it. It's an error (IMO) to call the ~
version a relative path.
Talking about things being "relative to an environment variable" is just confusing. It's bad practice to use different English-language meanings of terms that have specific technical meanings in the context you're using them in.
On a broken system, with HOME=a/relative/path
, ~/foo
would expand to a relative path. This would not be a usable setup at all.
find /tmp/test -name '*.txt' \
-exec bash -c './thulac < "$(readlink -f {})" > "/mnt/tokenized/$(basename {})"' \;
Use find to search for files and to execute commands on the results. With bash -c 'command'
you are able to execute multiple $().
Use readlink -f {}
to create the full path to the result.
Use basename {}
to strip the path from the result.
Best Answer
For passing file paths as arguments to a command,
find
does this on its own with its-exec
option without anyxargs
trickery:That will find every file called
*.csv
in/home/user
and then executeyourcommand /home/user/a\ b.csv /home/user/my\ dir/c\ d\$2.csv ...
with all of the found files as arguments. Each file found is passed as a separate complete argument to the program, so there is no escaping or anything else required:yourcommand
gets many arguments which are each exactly the complete file path.Another approach is that some shells (
zsh
in particular) support more advanced globbing, where you could just write:and get exactly the above effect too.
If you really do want the escaped strings themselves, rather than to run a command directly, you can use
bash
's built-inprintf
:The
%q
format specification expands to a shell-escaped version of the string argument. With many argumentsprintf
repeats the format string for all of them, so this produces space-terminated escaped strings of all the arguments to thebash -c
command.dummy
is used as the value of$0
, and"$@"
givesprintf
all the rest of the arguments, which are your (intact) file names. For your example this would output exactly/home/user/a\ b.csv /home/user/my\ dir/c\ d\$2.csv
.