2

I'm learning how to work with I/O Redirection in bash and tried some examples with the pipe like:

pwd | say
ls -l | grep "staff" > out.txt

But when I try using both pwd and open using pipe redirection, the command fails and I just receive open usage.

What I'm trying is: pwd | open

What is the correct way to open the current directory from bash?

romsearcher
  • 340
  • 5
  • 19
  • 1
    What `open` command is that? Does it read standard input? – Etan Reisner Apr 21 '15 at 16:51
  • 1
    `open` opens files from a shell [from Apple documentation](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/open.1.html). How can I check if it receives standard input? – romsearcher Apr 21 '15 at 16:55
  • 1
    If you want to open Finder for `pwd`, you can do `pwd | xargs open`. – khachik Apr 21 '15 at 17:00
  • @khachik Thank you, you should post this as an answer because this is what worked for me. – romsearcher Apr 21 '15 at 17:06
  • Note that `pwd | xargs open` is _not robust_, because it fails if the current directory path has embedded whitespace. – mklement0 Apr 22 '15 at 12:43

3 Answers3

7

With the benefit of hindsight, there are 2 distinct answers:


A: To answer the OP's question as asked with a view to understanding pipes and I/O streams:

echo . | xargs open

# Equivalent solution, using the special "$PWD" shell variable.
printf '%s\0' "$PWD" | xargs -0 open

is the most robust way to pass the current directory's path to the open CLI via a pipe in order to have it open that directory in OSX's file-system-browser GUI application, Finder.

Note that pwd | xargs open is NOT robust, because it fails if the current directory path has embedded whitespace - see below.

  • open requires input to be provided via command-line arguments rather than via the stdin input stream, as is the case here (via a pipe, |).
  • Thus, in order to translate stdin input to arguments, the standard xargs utility is needed.
  • xargs takes stdin input - coming from a pipe in this case - and invokes the command specified as its argument (open, in this case) with the tokenized stdin input as that command's arguments.
  • xargs splits by whitespace by default:
    • With . as the input, no splitting (or interpretation by the shell) occurs, so it can just be echoed to xargs.
    • By contrast, the special $PWD shell variable, which always contains the current dir.'s full path, may contain embedded whitespace, so extra steps are needed to ensure that it's passed to open as a single argument:
      • printf '%s\0' "$PWD" prints the current dir.'s full path terminated with a NUL byte (0x0).
      • Complementarily, xargs -0 splits stdin input into tokens by NUL - resulting in a single token in this case, preserving the value of the single input line - containing $PWD - as is. This is safe to do, because NUL is not a legal byte in filenames.
        • Note: -0 is a nonstandard extension to the POSIX standard for xargs, but it's implemented in both BSD xargs (as aused on OSX) and GNU xargs (as used on Linux). Remaining POSIX-compliant[1], the next best thing is to use line-based tokenizing with the -I option as follows:
          printf '%s' "$PWD" | xargs -I % open %

Thus, in effect the above solutions are equivalent to (what xargs ultimately executes - see next section for an explanation):

open . 

# Equivalent solution.
open "$PWD"

[1] xarg's -I option requires a POSIX system that is also XSI-compliant. If anyone can explain to me what that means in practical terms, I'd be grateful.


B: To provide the best answer with no constraints on techniques employed:

open .

open expects arguments rather than stdin input, and . succinctly and most efficiently represents the current directory, causing open to display the contents of the current folder in Finder.

An equivalent, but more verbose solution is to pass the special shell variable $PWD, which always contains the full path of the current directory (referenced in double quotes, so as to protect it from shell expansions:

open "$PWD"
mklement0
  • 382,024
  • 64
  • 607
  • 775
5

man open:

-f  Reads input from standard input and opens the results in the
    default text editor.  End input by sending EOF character (type
    Control-D).  Also useful for piping output to open and having
    it open in the default text editor.

Same manual, under "Examples":

ls | open -f writes the output of the 'ls' command to a file in /tmp and opens the file in the default text editor (as determined by LaunchServices).

You can therefore do pwd | open -f

that other guy
  • 116,971
  • 11
  • 170
  • 194
  • I tried your solution and it opens a new file in the text editor with the current directory written in it. But what I am attempting is for Finder to open the current directory. For example if I use: `open /Users/MyUser` Finder will open the directory (in Finder). – romsearcher Apr 21 '15 at 17:04
  • 1
    @romsearcher That would not involve pipes or redirection at all. You would use `open .` or equivalently, `open "$(pwd)"` – that other guy Apr 21 '15 at 17:12
  • Yes, you are right, the pipe is not necessary but I was trying to understand the pipe usage and wondered why the pipe did not work in this setting. – romsearcher Apr 21 '15 at 17:16
  • 2
    Arguments and pipes are separate things. You can convert piped data to arguments with `xargs` and arguments to piped data with `echo`. – that other guy Apr 21 '15 at 17:58
0

If you want to open Finder for pwd, you can do pwd | xargs open.

khachik
  • 28,112
  • 9
  • 59
  • 94
  • That'll break with paths that have embedded spaces. If involving a pipe and `xargs` is really needed, use `pwd | xargs -I {} open {}`. However, as @thatotherguy has already pointed out in a comment on his own answer, it is simpler to do `open "$(pwd)"`, or, better, `open "$PWD"`, or, best, `open .` – mklement0 Apr 21 '15 at 19:30
  • @mklement0 this is not a solution to some real life problem, the OP is trying to understand pipes and while `open .` is the most straightforward way to open a directory, it is not answering this question. – khachik Apr 21 '15 at 20:44
  • Agreed. However, `pwd | xargs -I {} open {}` _is_ answering the question _robustly_ - unlike `pwd | xargs open`. (If you need maximum robustness, use `printf '%s\0' "$PWD" | xargs -0 open`). That said, the mark of a good answer is to not just provide an answer to what was _directly_ asked for, but to point to better alternatives - but now our comments have that covered, I think. – mklement0 Apr 21 '15 at 20:48