How do you pass a file or folder containing whitespace as an argument to a command-line program in a GNU/Linux or Cygwin environment?

12
2014-01
  • rmiesen

    There are occasions when you are working with files and folders that contain spaces in them. The problem is any time you try and pipe files / folders containing whitespace to another command-line program, the files / folders containing whitespace are interpreted as separate arguments rather than as a single argument. For example, consider the following directory tree:

    Folder With Spaces
    Folder With Spaces/FolderWithoutSpaces
    Folder With Spaces/FolderWithoutSpaces/file with spaces.txt
    FolderWithoutSpaces
    FolderWithoutSpaces/fileWithoutSpaces.txt
    

    If you try and run a shell command such as "grep 'some text' $(find . -type f)", you'll get the following output:

    grep: ./Folder: No such file or directory
    grep: With: No such file or directory
    grep: Spaces/FolderWithoutSpaces/file: No such file or directory
    grep: with: No such file or directory
    grep: spaces.txt: No such file or directory
    

    The big question is, how do you pipe files / folders that have whitespace in them as arguments to a command line program?

  • Answers
  • sadbox

    You would be better off using the -exec flag and quoting your arguments. Example:

    find . -type f -exec grep stuff '{}' \;

    The quotes will keep the spaces from being interpreted and you don't have to pipe everything through xargs unnecessarily.

    From the manpage:

     -exec command ;
                  Execute command; true if 0 status is returned.  All following arguments to find are taken to be arguments to the command until  an  argument
                  consisting  of  `;'  is encountered.  The string `{}' is replaced by the current file name being processed everywhere it occurs in the argu‐
                  ments to the command, not just in arguments where it is alone, as in some versions of find.  Both of these constructions might  need  to  be
                  escaped  (with  a `\') or quoted to protect them from expansion by the shell.  See the EXAMPLES section for examples of the use of the -exec
                  option.  The specified command is run once for each matched file.  The command is executed in the starting directory.   There  are  unavoid‐
                  able security problems surrounding use of the -exec action; you should use the -execdir option instead.
  • rmiesen

    Pipe in your arguments using xargs by delimiting your command line arguments in the preceding program with a null character passing the "-0" option to xargs, such as follows:

    find . -type f -print0 | xargs -0 grep -l "some text"
    

    This command will pass in any files / folders with whitespaces in them as single arguments rather than separate arguments.

  • Dustin Anderson

    Use the backslash character '\' preceeding the whitespace:

    [randerson@localhost ~]$ mkdir Folder\ With\ Spaces
    [randerson@localhost ~]$ ls | grep Folder\ With\ Spaces
    Folder With Spaces
    [randerson@localhost ~]$ 
    
  • Bradd Szonye

    Enclose the file names in (single or double) quotation marks:

    $ mkdir "Folder With Spaces"
    $ ls | grep "Folder With Spaces"
    Folder With Spaces
    $ ls | grep 'Folder With Spaces'
    Folder With Spaces
    

    The shell will expand variables inside double quotation marks:

    $ FOO=With
    $ ls | grep "Folder $FOO Spaces"
    Folder With Spaces
    

    You can also quote $(...) expansions if the result is a single filename:

    $ ls -d "$(echo -n Folder With Spaces)"
    Folder With Spaces
    

    This will only work for single file names; for multiple files, use find -exec or xargs as suggested in the other answers.


  • Related Question

    linux - How to join files on the command line without creating temp files?
  • dggoldst

    I have two files in a Linux / Bash environment:

    # Example data
    $ cat abc
    2       a
    1       b
    3       c
    
    $ cat bcd
    5       c
    2       b
    1       d
    

    I'm trying to join the two files on the first column. The following does not work because the input files must be sorted on the match field.

    # Wrong: join on unsorted input does not work
    $ join abc bcd
    

    I can get around this by creating two temp files and joining them

    $ sort abc > temp1
    $ sort bcd > temp2
    $ join temp1 temp2
    1 b d
    2 a b
    

    But is there a way to do this without creating temp files?


  • Related Answers
  • dggoldst

    The following will work in the bash shell:

    # Join two files
    $ join <(sort abc) <(sort bcd)
    1 b d
    2 a b
    

    You can join on any column as long as you sort the input files on that column

    # Join on the second field
    $ join -j2 <(sort -k2 abc) <(sort -k2 bcd)
    b 1 2
    c 3 5
    

    The -k2 argument to sort means sort on the second column. The -j2 argument to join means join on the second columns. Alternatively join -1 x -2 y file1 file2 will join on the xth column of file1 and the yth column of file2.

  • Aaron F.

    Zsh answer:

    join =(sort abc) =(sort bcd)
    
  • jianpx

    This will work in bash shell:

    # Join two files
    $ sort abc | join - <(sort bcd)
    1 b d
    2 a b
    

    OR

    # Join two files
    $ sort bcd | join <(sort abc) -
    1 b d
    2 a b
    

    Because join can read standard input by using '-'.