I'm trying to write a script that I can run from the context menu in Caja (a clone of Nautilus). Its purpose is to pass the files that are selected in the file manager to a given program (for example, 7zip). A list of selected files is provided in the system variable $CAJA_SCRIPT_SELECTED_FILE_PATHS, separated by newlines. I want to pass each line of this variable to the program as an argument, even if they contain spaces.

After failing at quote-wrapping, I tried the following line:

echo "$CAJA_SCRIPT_SELECTED_FILE_PATHS" | xargs -d "\n" 7z a archive.7z

While it worked for 7zip, I changed the script so that the arguments are passed to a program I wrote and something went wrong, so I want a way to execute this in a terminal to get output from the program. I was using xterm -hold -e, but I haven't been able to make a command with a pipe in it execute this way because the shell will try to pipe output from xterm. I also tried shell redirection (by adding > log.txt to the end of the line), and it made a file for 7zip's usual output but a blank file for my program, which outputs messages just fine in the terminal.

Finally, I want a POSIX-compliant (or otherwise standard) solution so that it will work the same way on BSD and Linux.

EDIT: To clarify, I want to change some thing like this:

/path/with/a space

Into what I would hypothetically get from something like this:

char *argv[]={"/path/with/a space", "/another/path"};

EDIT2: That's how it should be in the program recieving the arguments, not the shell!


3 Answers 3


If you are open to using bash, you could set IFS to new line and read from a here-string to split CAJA_SCRIPT_SELECTED_FILE_PATHS into an array. You can then access array elements individually or in a loop(using "${a[@]}"). Embedded spaces will be preserved.

b c
IFS=$'\n' read -d '' -r -a a <<< "$CAJA_SCRIPT_SELECTED_FILE_PATHS"
printf "%s\n" "${a[0]}"
printf "%s\n" "${a[1]}"
b c
printf "%s\n" "${a[@]}"
b c

Here's a way to read stdin and split on newlines, keeping whitespace intact:

I tested with dash

while IFS= read -r line; do
    set -- "$@" "$line"
printf "have arg '%s'\n" "$@"
  • The question was to take a variable and remove newlines.
    – Wutaz
    Sep 24, 2013 at 20:08
  • POSIX-compliant shells don't have arrays. The positional parameters array-like structure is as close as you'll get. Sep 24, 2013 at 20:22
  • See edit, and consider reading the rest of the question too.
    – Wutaz
    Sep 24, 2013 at 20:27
  • In place of printf, substitute your program of choice. The "$@" is the key bit here. I don't think I have anything to add or remove from this answer.' Sep 24, 2013 at 23:51
  • It doesn't even include the variable I need to read from. It's completely irrelevant.
    – Wutaz
    Sep 25, 2013 at 14:25

While trying to make something useful out of glenn jackman's answer, I figured out what $IFS is. It seems that was all I needed.

I now have this script:

uxterm -hold -e ./program_to_test $CAJA_SCRIPT_SELECTED_FILE_PATHS

I confirmed that it worked by replacing ./program_to_test with a BASH script I wrote that prints its arguments with individual highlighting. When I ran the script above in Caja, an xterm window appeared and the paths to the selected files were all printed out highlighted, with gaps in the highlight between paths but not between words in filenames. Ergo, this makes each line into an argument.

I'm actually surprised that there was a method that required no tools outside of a Bourne-like shell. Perhaps I haven't given this tool enough credit.

Not the answer you're looking for? Browse other questions tagged .