Aeronautix
Aeronautix

Reputation: 316

How to pipe $'\n' from sed into xargs echo correctly?

Problem

I want to convert a string of paths (where each path may contain escaped spaces) into a printed list of paths. I'm mainly using echo and sed, and the problem lies therein (see below).

For example, I want these three files:

one two three\ two\ one

To be printed on three lines:

one
two
three two one

Problem with "sed" and "echo"

(1) These are three sample files: "one", "two", and "three two one".

echo "one two three\ two\ one"

# one two three\ two\ one

(2) I replace the whitespace that separates files with a newline.

echo "one two three\ two\ one" | sed 's/\([^\]\) /\1$'"'"'\\n'"'"'/g'

# one$'\n'two$'\n'three\ two\ one

(3) I test that indeed, "echoing" the output of the above results in the output I want.

echo one$'\n'two$'\n'three\ two\ one

# one
# two
# three two one

Combining (2) and (3), the functionality breaks using "xargs echo":

echo "one two three\ two\ one" | sed 's/\([^\]\) /\1$'"'"'\\n'"'"'/g' | xargs echo

# one$\ntwo$\nthree two one

How to fix the sed substitution?

How can the sed substitution be fixed so that echoing the output gives:

one
two
three two one

I'm looking for a solution that uses primarily "echo" and "sed" (not looking for other solutions).

I also can't use "echo -e" to interpret escaped characters.

Upvotes: 2

Views: 793

Answers (3)

that other guy
that other guy

Reputation: 123550

Here's how you show your filenames on screen separated by linefeeds:

find "$PWD" -maxdepth 1 -print

If you wanted to process them in some way, you should pass them \0 separated (using -print0) or use find -exec. Trying to format them as shell words is not the way to go.

The reason why echo doesn't show the value you expect is because $'\n' is Bash syntax meaning literal linefeed. It is not echo syntax, and echo is not involved in interpreting it.

For dash, xargs and other more traditional tools, $'\n' is just a weird way of formatting the literal characters dollar-backslash-n ($\n).

Since you're using xargs echo, bash is not involved, so you get $\n out instead. The solution is not to try to format data into code in such a way that the code will evaluate back to the original data. The solution is to skip that step entirely and just let data be data, such as in the initial example.

Upvotes: 1

chipfall
chipfall

Reputation: 360

Not a solution but an answer to the comment you made on your own post "on why xargs echo" isn't working, see this answer regarding what $'\n' is:

https://stackoverflow.com/a/4128305/4092051

Upvotes: 0

Vicctor
Vicctor

Reputation: 833

This command works for me:

echo "one two three\ two\ one" | sed 's/\([^\]\) /\1\n/g' | sed 's/\\ / /g' | xargs -L1 -I {} echo -{}-

The trick was

  • replace \\n with \n
  • use -L1 in xargs parameters
  • I used {} and -I{} just to demonstrate that echo is called for each line

Upvotes: 0

Related Questions