user6587018
user6587018

Reputation: 11

While using awk showing fatal : cannot open pipe ( Too many open files) error

I was trying to do masking of file with command 'tr' and 'awk' but failing with error fatal: cannot open pipe ( Too many open pipes) error. FILE has approx 1000000 records quite a huge number. Below is the code I am trying :-

awk - F "|" - v OFS="|" '{ "echo \""$1"\" | tr \" 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" \" QWERTYUIOPASDFGHJKLZXCVBNM9876543210mnbvcxzlkjhgfdsapoiuytrewq\"" | get line $1}1' FILE.CSV > test.CSV

It is showing error :-

awk: (FILENAME=- FNR=1019) fatal: cannot open pipe `echo ""TTP_123"" | tr "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "QWERTYUIOPASDFGHJKLZXCVBNM9876543210mnbvcxzlkjhgfdsapoiuytrewq"' (Too many open pipes)

Please let me know what I am doing wrong here Also a Note any number of columns could be used for masking and can be at any positions in this example I have taken 1 and 2 column positions but it could be 3 and 10 or 5,7,25 columns Thanks AJ

Upvotes: 0

Views: 986

Answers (3)

Kevin
Kevin

Reputation: 56129

First things first, you can't have a space between - and F or v.

I was going to suggest sed, but as you only want to translate the first column, that's not as easy.

Unfortunately, awk doesn't have built-in tr functionality, so you'd have to use the shell like you are and just close the pipe:

awk -F "|" -v OFS="|" '{ 
    command="echo \"\\"$1"\\\" | tr \" 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" \" QWERTYUIOPASDFGHJKLZXCVBNM9876543210mnbvcxzlkjhgfdsapoiuytrewq\""
    command | getline $1
    close(command)
}1' FILE.CSV > test.CSV

However, I suggest using perl, which can do field splitting and character translation:

perl -F'\|' -lane '$F[0] =~ tr/0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/QWERTYUIOPASDFGHJKLZXCVBNM9876543210mnbvcxzlkjhgfdsapoiuytrewq/; print join("|", @F)' FILE.CSV > test.CSV

Or, for a shorter command line, just put the program into a file, drop the e in -lane and use the file name instead of the '...' command.

Upvotes: 1

glenn jackman
glenn jackman

Reputation: 247022

This does not answer your question, but you can implement tr as an awk function that would save having to spawn lots of external processes

$ cat tr.awk

function tr(str, from, to,       s,i,c,idx) {
    s = ""
    for (i=1; i<=length($str); i++) {
        c = substr(str, i, 1)
        idx = index(from, c)
        s = s (idx == 0 ? c : substr(to, idx, 1))
    }
    return s
}
{
    print $1, tr($1,
        " 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
        " QWERTYUIOPASDFGHJKLZXCVBNM9876543210mnbvcxzlkjhgfdsapoiuytrewq")
}

Example:

$ printf "%s\n" hello wor-ld | awk -f tr.awk
hello KGCCN
wor-ld 3N8-CF

Upvotes: 0

karakfa
karakfa

Reputation: 67507

you can do the mapping in awk instead of making a system call for each line, or perhaps simply

paste -d'|' <(cut -d'|' -f1 file | tr '0-9' 'a-z') <(cut -d'|' -f2- file)

replace the tr arguments with yours.

Upvotes: 0

Related Questions