Reputation: 18410
If I pass in a path from the command line, "~" expands to my home directory:
(defn -main
"I don't do a whole lot ... yet."
[& args]
(doseq [arg args]
(println arg)))
britannia:uberjar srseverance$ java -jar args-0.1.0-SNAPSHOT-standalone.jar ~/158.clj
/Volumes/Macintosh HD/Users/srseverance/158.clj
But if I try to use a path-file containing ~, I can't find the file.
user> (with-open [r (clojure.java.io/reader "~/158.clj")]
(doall (line-seq r)))
FileNotFoundException ~/158.clj (No such file or directory) java.io.FileInputStream.open0 (FileInputStream.java:-2)
How do I take a string like, "~/158.clj" and get back something clojure.java.io/reader
can use, such as "/Volumes/Macintosh HD/Users/srseverance/158.clj"?
Upvotes: 4
Views: 2558
Reputation: 4748
You can define
(defn expand-home [s]
(if (.startsWith s "~")
(clojure.string/replace-first s "~" (System/getProperty "user.home"))
s))
and use it to resolve home directory:
(clojure.java.io/reader (expand-home "~/158.clj"))]
You could also look into fs library definition of expand-home, which solves the ~foo
problem outlined in bfontaine's comment below:
(let [homedir (io/file (System/getProperty "user.home"))
usersdir (.getParent homedir)]
(defn home
"With no arguments, returns the current value of the `user.home` system
property. If a `user` is passed, returns that user's home directory. It
is naively assumed to be a directory with the same name as the `user`
located relative to the parent of the current value of `user.home`."
([] homedir)
([user] (if (empty? user) homedir (io/file usersdir user)))))
(defn expand-home
"If `path` begins with a tilde (`~`), expand the tilde to the value
of the `user.home` system property. If the `path` begins with a
tilde immediately followed by some characters, they are assumed to
be a username. This is expanded to the path to that user's home
directory. This is (naively) assumed to be a directory with the same
name as the user relative to the parent of the current value of
`user.home`."
[path]
(let [path (str path)]
(if (.startsWith path "~")
(let [sep (.indexOf path File/separator)]
(if (neg? sep)
(home (subs path 1))
(io/file (home (subs path 1 sep)) (subs path (inc sep)))))
path)))
Upvotes: 11
Reputation: 759
Addressing bfontaine's comment, we can get correct results for ~user
and ~root
by asking the system instead:
(require '[clojure.java.shell :refer [sh]])
(defn bash [command]
(sh "bash" "-c" command))
(defn expand [path]
(-> (str "echo -n " path)
bash
:out))
(expand "~")
;; => /home/teodorlu
(expand "~teodorlu")
;; => /home/teodorlu
(expand "~root")
;; => /root
Though, just use this for trusted code!
(expand "`cat ~/.passwords`")
;; => All my passwords!
Upvotes: 3