I would avoid working on tabular data with sed
as it's difficult to correctly address the exact positions in the data that you want to modify. The sed
utility is more suitable for processing unstructured data like text.
Using Miller (mlr
; a tool specifically made for working with structured data) to append the string _All
to the end of the data in the Trait
field of each TSV record:
$ mlr --tsv put '$Trait .= "_All"' file
Marker Pvalue Trait Chr Pos
S3_16887238 6.172847e-09 Total_Soil_S_All 3 16887238
S3_16887238 6.172847e-09 Total_Soil_Pa_All 3 16887238
S3_16887238 6.172847e-09 Total_Soil_Cl_All 3 16887238
Use mlr
with its -I
option to do the change in-place.
Would you need to ensure that you are modifying the field only if it starts with the string Total_Soil
, then use
mlr --tsv put '$Trait =~ "^Total_Soil" { $Trait .= "_All" }' file
With awk
, appending the string _All
to the end of the data in the 3rd tab-delimited field of each record:
$ awk -F '\t' 'BEGIN { OFS=FS } NR > 1 { $3 = $3 "_All" }; 1' file
Marker Pvalue Trait Chr Pos
S3_16887238 6.172847e-09 Total_Soil_S_All 3 16887238
S3_16887238 6.172847e-09 Total_Soil_Pa_All 3 16887238
S3_16887238 6.172847e-09 Total_Soil_Cl_All 3 16887238
The trailing 1
at the end of the awk
code causes the modified record to be unconditionally outputted. It is, in a way, a short-hand way of writing { print }
. Note that we explicitly need to avoid modifying the header. We do this by testing using NR > 1
and modifying the field only if the test evaluates to true (NR
is the ordinal number of the current record).
Redirect the output to a new file and then rename the new file to the original name. Or, if you are using GNU awk
, use -i inplace
as described in another question+answer.
Again, if you need to ensure that you only modify the 3rd field if it starts with the string Total_Soil
, then use
awk -F '\t' 'BEGIN { OFS=FS } NR > 1 && $3 ~ /^Total_Soil/ { $3 = $3 "_All" }; 1' file
Using Perl in pretty much the same way as awk
:
$ perl -F'\t' -e 'BEGIN { $" = "\t" } if ($. > 1) { $F[2] .= "_All" } print "@F"' file
Marker Pvalue Trait Chr Pos
S3_16887238 6.172847e-09 Total_Soil_S_All 3 16887238
S3_16887238 6.172847e-09 Total_Soil_Pa_All 3 16887238
S3_16887238 6.172847e-09 Total_Soil_Cl_All 3 16887238
Ensuring we only modify Total_Soil
data:
perl -F'\t' -e 'BEGIN { $" = "\t" } if ($. > 1 && $F[2] =~ /^Total_Soil/) { $F[2] .= "_All" } print "@F"' file