Saif
Saif

Reputation: 3452

Multiline output to single line concatenation with delimiter string

I use this command to get a list of all the files that has changed in a pull-request.

git diff --name-only HEAD master

Sample output:

my/repo/file1.java
my/repo/file3.java
my/repo/file5.java

I would like to convert this output to the following:

file:my/repo/file1.java||file:my/repo/file3.java||file:my/repo/file5.java

so that I can run code analysis only on these files from IntelliJ IDEA.

What have I tried so far?

git diff --name-only HEAD master |  sed -e 's/^/file:/'  | paste -s -d "||" -

This gives me the following output:

file:my/repo/file1.java|file:my/repo/file3.java|file:my/repo/file5.java

Notice the single |.

Also, please simplify the command if possible.

Edit: None of the files will have a whitespace or a newline in the name.

Upvotes: 3

Views: 379

Answers (7)

RARE Kpop Manifesto
RARE Kpop Manifesto

Reputation: 2805

"${input….}" |
{m,g}awk 'sub("^", "file:", $!(NF = NF))^+!+--NF' \
          FS='\n|[|]+[^:/]+:$' RS='^$' OFS='||file:' 

 
my/repo/file1.java
my/repo/file3.java
my/repo/file5.java
 
 
file:my/repo/file1.java||file:my/repo/file3.java||file:my/repo/file5.java
 

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203403

$ git diff --name-only HEAD master |
    awk '{printf "%sfile:%s", sep, $0; sep="||"} END{if (sep) print ""}'
file:my/repo/file1.java||file:my/repo/file3.java||file:my/repo/file5.java

The above:

  1. Will not print a blank line given no input, it'll produce no output, and
  2. Does not read the whole input into memory, it just reads 1 line at a time, and
  3. Uses a mandatory POSIX tool, awk, with no non-portable extensions.

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 140970

The list of delimiters to paste is a list of consecutive single-character delimiters to be used for columns.

$ paste -d 'abc' <(seq 0 3) <(seq 3 6) <(seq 6 9) <(seq 9 12)
0a3b6c9
1a4b7c10
2a5b8c11
3a6b9c12

There is a simple trick - you can make paste join lines with a single-char delimiter, and then replace the single char by multi-char that you want to have.

git diff --name-only HEAD master | paste -sd '|' | sed 's/|/||/g'

You can also use bash to replace newlines with ||. Fun fact: command substitution $(..) removes trailing newlines.

a=$(git diff --name-only HEAD master); echo "${a//$'\n'/||}"

Upvotes: 0

anubhava
anubhava

Reputation: 785108

You may try this git... | awk solution:

git diff --name-only HEAD master |
awk '{printf "%sfile:%s", (NR>1?"||":""), $0} END{print ""}'

Or a more nifty awk solution (works with BSD/Mac awk also):

git diff --name-only HEAD master |
awk -v RS= -v OFS='||' '{$1=$1} 1'

Upvotes: 2

Fravadona
Fravadona

Reputation: 16960

You can also do it with awk

git diff --name-only HEAD master |
awk 'NR > 1 {printf("||")} {printf("file:%s",$0)} END{print ""}'

What this awk does is:

  • for all input lines but the first, output: ||
  • for all input lines, output: file: + <input line content>
  • when there's no more input lines to read, output a newline character

remark: the END{print ""} is unrequited when you do out=$(git .. | awk ...)

Upvotes: 2

Shawn
Shawn

Reputation: 52344

Since you're on a Mac, might as well use zsh instead of its ancient outdated version of bash (Plus no using extra processes or programs, just zsh substitutions):

#!/usr/bin/env zsh                                                                                                                                                                                                                               

#data=$(git diff --name-only HEAD master)

data="my/repo/file1.java                                                                                                                                                                                                                       
my/repo/file3.java                                                                                                                                                                                                                               
my/repo/file5.java"

typeset -a files=( "${(@f)data}" ) # Split on newlines
combined=${(j:||:)files[@]/#/file:} # Add file: to every element and join with ||

# file:my/repo/file1.java||file:my/repo/file3.java||file:my/repo/file5.java
print "$combined" 

Upvotes: 0

sseLtaH
sseLtaH

Reputation: 11217

Using sed

$ git diff --name-only HEAD master| sed s'/^/file:/;:a;N;s/\n/||file:/;ba'
file:my/repo/file1.java||file:my/repo/file3.java||file:my/repo/file5.java

Upvotes: 1

Related Questions