Hi Hongyi
Take a look at
NotebookInformation[] // InputForm
it is a List of Rule. We are interested in the "FileName" Rule so extract it (similar to how one would extract a solution from Solve)
"FileName" /. NotebookInformation[]
(* FrontEnd`FileName[{$RootDirectory, "Users", "rohit", "Documents",
"Mathematica"}, "test.nb", CharacterEncoding -> "UTF-8"] *)
We are interested in the first argument, the List passed to FrontEnd`FileName which are components of the path, and the second argument which is the file name. We can extract them using the pattern
_[{path__}, fileName_, __]
The first _ matches any head, in this case FrontEnd`FileName. The {path__} matches the first argument as a list of something and binds it to path. The fileName_ matches the second argument and binds it to fileName, the __ matches the rest of the arguments which we don't care about so it is not bound to anything. We now have the pieces we need
"FileName" /. NotebookInformation[] /. _[{path__}, fileName_, __] :> {path, fileName}
(* {"/", "Users", "rohit", "Documents", "Mathematica", "test.nb"} *)
So we pass it to FileNameJoin to add the right directory delimiters for the OS
"FileName" /. NotebookInformation[] /. _[{path__}, fileName_, __] :> FileNameJoin@{path, fileName}
(* "/Users/rohit/Documents/Mathematica/test.nb" *)
One thing to be aware of is that path is a Sequence not a List so there is no need to Append fileName to it before passing to FileNameJoin.
"FileName" /. NotebookInformation[] /. _[{path__}, fileName_, __] :> path
(* Sequence["/", "Users", "rohit", "Documents", "Mathematica"] *)
Hope you enjoy your Wolfram Language journey. 千里之行,始于足下