AnnaSchumann
AnnaSchumann

Reputation: 1271

Find and replace confined to a specific column (one-liner)

Is there a way (in a one-liner) to confine find and replace to within a specific column of a tab-delimited .txt file?

For example:

perl -pe 's/A/B/g;'

But which only finds and replaces 'A' with 'B' within column-2 and ignores all other instances of A, converting this:

1   A   A2
2   A   A
3   B   B1
4   A   B
5   A   A
6   B   A3
7   A   A
8   C   A
9   E   B
10  D   B
11  A   C6
12  A   G
13  B   L
14  A   E
15  B   A
16  A   A

Into:

1   B   A2
2   B   A
3   B   B1
4   B   B
5   B   A
6   B   A3
7   B   A
8   C   A
9   E   B
10  D   B
11  B   C6
12  B   G
13  B   L
14  B   E
15  B   A
16  B   A

Upvotes: 0

Views: 1182

Answers (3)

Benjamin W.
Benjamin W.

Reputation: 52162

A sed one-liner

$ sed 'h;s/^.*\t\(.*\)\t.*$/\1/;y/A/B/;G;s/\(.*\)\n\(.*\t\).*\(\t.*\)/\2\1\3/' infile
1       B       A2
2       B       A
3       B       B1
4       B       B
5       B       A
6       B       A3
7       B       A
8       C       A
9       E       B
10      D       B
11      B       C6
12      B       G
13      B       L
14      B       E
15      B       A
16      B       A

Explained:

# Copy pattern space to hold space
h

# Remove first and third column from pattern space
s/^.*\t\(.*\)\t.*$/\1/

# Transliterate A to B (can use s/// for more complex substitutions)
y/A/B/

# Append hold space to pattern space
G

# Replace second column with transliterated value
s/\(.*\)\n\(.*\t\).*\(\t.*\)/\2\1\3/

A sed-free alternative

$ paste <(cut -f 1 infile) <(cut -f 2 infile | tr A B) <(cut -f 3 infile)

This uses paste , cut and tr with process substitution. The tr can of course be replaced by a sed substitution for more complex changes.

Upvotes: 1

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89567

You can write this:

perl -lane '$F[1]=~tr/A/B/;print join("\t", @F)' file

Upvotes: 2

Sobrique
Sobrique

Reputation: 53488

Something like this will transform the second field of a tab separated row.

perl -lne '@row = split /\t/; $row[1] =~ s/A/B/; print join ( "\t", @row );' 

Upvotes: 2

Related Questions