7

What is the easiest way to replace a column in a file? basically, my file.txt has 3 columns separated by ,.

How can I change the second column with a bash script?

SveUJW24ibppfePgYeYHz7fC0,64BzZdqrYY7Tx8sbj5tmEW,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,gTdmvjmahIOoyzmrttVMvTc1ER0bt,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,LzLtoEg18E1brm66dPjcHZfpI107nn4h,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ
7cjW5DZlXw1LYzVugbVyqfxRX,i7B4Q9w8h5anmMW87DfIBEm0AuNjbLGq,XttE1In9eZQ8puJVUriuNvx2AJAxviGf
XiLE8r9AMqy5YZQ9BbIS6m559,ToT2wbQdpNNySPxP1Tgz1,DssiszVBa05pbVDSOXNRaFXRxw0eZKHf
Sygrl5287BViOn0uQ9uCYipB1,TEYnXl6APWGbm9ckLCcHFUJzk7qS8JXH,sD2O46sbh1yVIluoyn6Zm2OKXYe05vV9
Qi6DxJ96M0hxNe4cgux3iJ1aS,LK3GHTpuo9kbmK9McRN4sFRQTGh2DU8J,wk2eF3f9xk5HowLzDIL3hCCNSmx8Uwi8
ZIX7qp5IIPekA0kzBdFR4IUQZ,9m9lEjfiotQ97s3uVN8EEP7Y1JmpgAk7,99ilfJWoJEBsKOfYI3buFfher07OCz6Y

Update replace with another string in a variable. let's say var=new-sting.

Actually, I was thinking I could do something like this:

sed "s/,[^,]*/,$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)/" file.txt

But it is not working as expected. I am having the same string over and over.

6
  • Will it be the same replacement string for every line?
    – Byte Commander
    May 19 '17 at 9:06
  • @ByteCommander yes, in my script I will handle the variable
    – dmx
    May 19 '17 at 9:07
  • So you want to process just one line, then do some application logic to update the replacement variable and then process the next line? Otherwise there are tools to process the whole file at once.
    – Byte Commander
    May 19 '17 at 9:08
  • @ByteCommander I want to replace by another random string. It can be done in one line
    – dmx
    May 19 '17 at 9:11
  • 1
    If you want to replace with a different random string each line, I'd suggest using something like perl's Bytes::Random::Secure module - see for example Filling up column of text file with random data using bash May 19 '17 at 9:16
7

Assuming that file.txt contains lines of text that are divided into three columns with commas and that there are no additional commas anywhere, so each line has exactly two of them:

replacement="my string"
sed "s/,.*,/,$replacement,/" file.txt

Output:

SveUJW24ibppfePgYeYHz7fC0,my string,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,my string,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,my string,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ
7cjW5DZlXw1LYzVugbVyqfxRX,my string,XttE1In9eZQ8puJVUriuNvx2AJAxviGf
XiLE8r9AMqy5YZQ9BbIS6m559,my string,DssiszVBa05pbVDSOXNRaFXRxw0eZKHf
Sygrl5287BViOn0uQ9uCYipB1,my string,sD2O46sbh1yVIluoyn6Zm2OKXYe05vV9
Qi6DxJ96M0hxNe4cgux3iJ1aS,my string,wk2eF3f9xk5HowLzDIL3hCCNSmx8Uwi8
ZIX7qp5IIPekA0kzBdFR4IUQZ,my string,99ilfJWoJEBsKOfYI3buFfher07OCz6Y

This will process all lines at once and replace the middle column with the same value each time. The changed content will be printed to the terminal by default, if you want to modify file.txt in place instead, write sed -i instead of plain sed.


If you need to update the replacement variable for each line anyhow (here a new random string for each line), you can loop over the lines like this:

while read line ; do
    replacement="random number $RANDOM"
    sed "s/,.*,/,$replacement,/" <<< "$line"
done < file.txt

Example output:

SveUJW24ibppfePgYeYHz7fC0,random number 27584,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,random number 2959,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,random number 5463,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ
7cjW5DZlXw1LYzVugbVyqfxRX,random number 12889,XttE1In9eZQ8puJVUriuNvx2AJAxviGf
XiLE8r9AMqy5YZQ9BbIS6m559,random number 3754,DssiszVBa05pbVDSOXNRaFXRxw0eZKHf
Sygrl5287BViOn0uQ9uCYipB1,random number 25375,sD2O46sbh1yVIluoyn6Zm2OKXYe05vV9
Qi6DxJ96M0hxNe4cgux3iJ1aS,random number 5284,wk2eF3f9xk5HowLzDIL3hCCNSmx8Uwi8

It's probably the easiest way to put this code snippet into a script file and then you ran redirect its output to a separate new file (not the original file from which you read!) like this:

bash my-replacement-script.sh > new-file.txt
6

I'd suggest an approach based on the perl Bytes::Random::Secure module, based on Filling up column of text file with random data using bash modified to use your desired mix of upper and lower case letters and decimal digits:

perl -MBytes::Random::Secure=random_string_from -F, -ane '
  BEGIN{$chars = join "", ("a".."z","A".."Z",0..9)}
  $F[1] = random_string_from($chars, 32);
  print join ",", @F
' file

Alternatively, if you want to use your /dev/urandom pipeline, one way to do that without external looping would be using a FIFO with awk's getline function:

  1. make the FIFO $ mkfifo _fifo

  2. execute your command, streaming its output to the FIFO

    $ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 > _fifo &
    

    or (eliminating the useless use of cat)

    $ tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 > _fifo &
    
  3. get lines from the FIFO and substitute them in to the lines of the target file

    $ awk '{getline $2 < "_fifo"} 1' FS=, OFS=, file
    
  4. remove the FIFO

    rm _fifo
    

Testing:

$ mkfifo _fifo
$ tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 > _fifo &
[1] 5815
$ awk '{getline $2 < "_fifo"} 1' FS=, OFS=, file
SveUJW24ibppfePgYeYHz7fC0,hpqBxCOYIj7eQ9MgbPNG69SY3X3iAJ7A,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,ACU1hyR8zGRfDMeUk4a6TFVcQvUAtZog,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,dkeKUnMYZepGcGMgdQc9IORa77Vtwr7w,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ
7cjW5DZlXw1LYzVugbVyqfxRX,UMjkPZAB3ElpOnXWnsQe9w1v0h6HMLPs,XttE1In9eZQ8puJVUriuNvx2AJAxviGf
XiLE8r9AMqy5YZQ9BbIS6m559,iz5tavnYqajwTokPCM4HJIsZlIloLcVy,DssiszVBa05pbVDSOXNRaFXRxw0eZKHf
Sygrl5287BViOn0uQ9uCYipB1,RHPFMgKoIGojvM6aTwb43lH4BAr8Jh5Y,sD2O46sbh1yVIluoyn6Zm2OKXYe05vV9
Qi6DxJ96M0hxNe4cgux3iJ1aS,fqTsEPr3PIPqIWPrb2uIl47QjXlSt3gL,wk2eF3f9xk5HowLzDIL3hCCNSmx8Uwi8
ZIX7qp5IIPekA0kzBdFR4IUQZ,uAFKvX5z2ik2i1AKh3wYp503xpNy8dxA,99ilfJWoJEBsKOfYI3buFfher07OCz6Y
rm _fifo
[1]+  Broken pipe             cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 > _fifo

With GNU awk, you can do the equivalent internally using getline with a co-process:

$ gawk '{"tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32" |& getline $2} 1' FS=, OFS=, file 
SveUJW24ibppfePgYeYHz7fC0,hKOYDf6lgEtVwzJvCl34eYu22m5bZ11e,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,bV9m4OgbTzDTJQanhS3BTmxr5gUcouDy,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,r9850TtXPJsLLNMupiwSPsqx7ovtb5ph,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ
7cjW5DZlXw1LYzVugbVyqfxRX,aRRVAecWxeTtt3WX36MIoFlMCvDcFb3a,XttE1In9eZQ8puJVUriuNvx2AJAxviGf
XiLE8r9AMqy5YZQ9BbIS6m559,BeCoCV4kMb8FUt6Y3RFxolI2CKqzbeuO,DssiszVBa05pbVDSOXNRaFXRxw0eZKHf
Sygrl5287BViOn0uQ9uCYipB1,WZ0hSxurp22dCdhV12Gjcms6rdx8hjM2,sD2O46sbh1yVIluoyn6Zm2OKXYe05vV9
Qi6DxJ96M0hxNe4cgux3iJ1aS,ujxdLQZo1vkCZnkUej6pLjZxVmN7XiTE,wk2eF3f9xk5HowLzDIL3hCCNSmx8Uwi8
ZIX7qp5IIPekA0kzBdFR4IUQZ,qxp3dwltN5Mxfece27Zvq2NqbjPlF358,99ilfJWoJEBsKOfYI3buFfher07OCz6Y
3

Using awk:

awk -v var="mystring" -F, 'BEGIN {OFS = FS} {$2 = var; print}'
  • -v: create a variable named var which contains the string "mystring"
  • -F,: use , as field separator
  • BEGIN {OFS = FS} set output field separator equal to field separator to keep the separator (comma) after replacement
  • {$2 = var; print} replace the field 2 (column 2) with var content; then print.

You can also change -v var="mystring" with something like -v var="$variable" which $variable is an variable in your environment.


Here is an example:

veUJW24ibppfePgYeYHz7fC0,64BzZdqrYY7Tx8sbj5tmEW,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,gTdmvjmahIOoyzmrttVMvTc1ER0bt,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,LzLtoEg18E1brm66dPjcHZfpI107nn4h,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ

let's run the command:

$ awk -v var="HERE-IS-MY-STRING" -F, 'BEGIN {OFS = FS} {$2 = var; print}' file.tx

veUJW24ibppfePgYeYHz7fC0,HERE-IS-MY-STRING,yL6mCP0Do28k4EoTZUfKfqNYiIhGxxkA
xyRG8Da6kY35xeIT492Lul7xu,HERE-IS-MY-STRING,ne6RIM2TeMQAax1GgzL7FeDrnQyHPH1i
sxTf13KlAnjtXodJouQ9V6m5b,HERE-IS-MY-STRING,GUnApYwwDCZxWGZtzKzTU6sJRgHlUUfQ

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.