This question already has an answer here:

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!

marked as duplicate by peterph, Anthon, slm Oct 10 '14 at 13:17

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.


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 '13 at 20:08
  • POSIX-compliant shells don't have arrays. The positional parameters array-like structure is as close as you'll get. – glenn jackman Sep 24 '13 at 20:22
  • See edit, and consider reading the rest of the question too. – Wutaz Sep 24 '13 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.' – glenn jackman Sep 24 '13 at 23:51
  • It doesn't even include the variable I need to read from. It's completely irrelevant. – Wutaz Sep 25 '13 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 or ask your own question.