-1

I'd like to sort based on the output of a mercurial (hg) command. The output from hg log is collapsed into 1 line when piping to another command but I want to keep separate lines.

Here's a minimum reproducible case:

# Initial setup
mkdir /tmp/hgbug; cd /tmp/hgbug; hg init; 
touch README.md; hg add README.md
h commit -m "initial commit"

# Bug - the echo command replaces a complex find command
echo '1a\n2b\n3c\n' | xargs -I % hg log --template '%' | sort

# Actual Output
# 1a2b3c

# Expected Output
# 1a
# 2b
# 3c

The interesting part is that mercurial doesn't collapse the lines when the output isn't piped or redirected.

echo '1a\n2b\n3c\n' | xargs -I % hg log --template '%'
# Actual Output
# 1a
# 2b
# 3c

How do I prevent mercurial from collapsing lines when redirecting output?

To clarify, here's a more complete example comparing the output of hg with echo using both xargs and a while loop.

#!/bin/bash
cd /tmp/hgbug

echo '# hg log - xargs'
echo $'1a\n2b\n3c' | xargs -I {} hg log --template "hg-{}" | sort

echo
echo '# plain echo - xargs'
echo $'1a\n2b\n3c' | xargs -I {} echo "echo-{}" | sort

echo
echo '# hg log - while read'
echo $'1a\n2b\n3c' | while read -r file; do hg log --template "hg-$file"; done | sort

echo
echo '# plain echo - while read'
echo $'1a\n2b\n3c' | while read -r file; do echo "echo-$file"; done | sort

That script outputs the following:

# hg log - xargs
hg-1ahg-2bhg-3c

# plain echo - xargs
echo-1a
echo-2b
echo-3c

# hg log - while read
hg-1ahg-2bhg-3c

# plain echo - while read
echo-1a
echo-2b
echo-3c
4
  • xargs sets a parameter for each line extracted from the input. It is up to the target program to decide how to handle multiple parameters. If you need one parameter at a time, don't use xargs; instead, use find ... -exec hg log --template {} \; or find ... | while read -r file; do hg log --template "$file"; done (note my use and omission of quotes).
    – AFH
    Commented Nov 12, 2017 at 23:27
  • I still don't understand where the output is getting collapsed. GNU xargs with the -I param implies -L 1, or one line per invocation. So, there's 3 hg log invocations. I'd like to stick with xargs to use the parallelism feature. If I use echo instead of hg, everything works as expected.
    – Joe
    Commented Nov 13, 2017 at 2:04
  • I added a more complete example comparing hg to echo to help illustrate the problem.
    – Joe
    Commented Nov 13, 2017 at 2:34
  • Turns out the while-read was a red-herring. The problem was hg log doesn't add trailing newlines when output is redirected. The behavior makes sense, but is surprising when trying to figure out the differences between interactive and redirected output.
    – Joe
    Commented Nov 13, 2017 at 3:20

1 Answer 1

0

hg log doesn't add a trailing newline to output when the --template flag is set and the shell command is redirected or piped to another command.

To make it work, you need to add the newline to the template string like so:

echo '1a\n2b\n3c\n' | xargs -I % hg log --template '%\n' | sort
# Output
1a
2b
3c

You must log in to answer this question.

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