Google says that "Ansvarig vardenhet" is Swedish for "Responsible care unit".
If that is true, then this print statement (and its twin further down) is lying.
They are not reading 'ansvarig_vardenhet_utf8.txt'; they are reading 'icd-10-codes.txt' and 'female1.txt'.
If you just need reassurance about what point your program has reached, then use something like print "P1\n"; and print "P2\n";. Otherwise, include the actual file names. Do not lie; it will just confuse the next person who works on the program.

As written, if the ICD file is missing, then your program will seem to run correctly, but will silently fail to do any replacements. Silent failure is not acceptable. die() is used to halt a program on a critical error; it is often coupled with or so that the die happens when the first part of a statement fails. The $! variable contains the reason for the failure. open(WIN, "icd-10-codes.txt") or die "Cannot open file: $!"; .
Some other changes that would be improvements, but are not mandatory:

You are not telling Perl whether to read or write the file, so it defaults to read. It is better to be explicit. open( WIN, '<', "icd-10-codes.txt" )

WIN is a "bareword" filehandle. We now encourage the use of a real variable for the filehandle. open( my $win_fh, '<', "icd-10-codes.txt" )

If you use a variable to hold the filename, then you can locate the actual filename at the top of the program, where such configurable info is usually located. It will also allow you to put the filename in the "die" error message, and in the "reading ansvarig_vardenhet_utf8.txt" line already discussed, without repeating yourself. my $icd_file = 'icd-10-codes.txt'; #print "Reading '$icd_file'\n"; open( my $win_fh, '<', $icd_file ) or die "Cannot open '$icd_file': $!";

By the way, the missing "strict" and "warnings" lines, and the missing '<' in "open", tell me that you are learning Perl from outdated material. I highly recommend Learning Perl or Modern Perl (or its free PDF).

Since we added "use strict", we now have to declare all variables, such as $line.
Also, $line needs to have its newline removed, otherwise the ICD description will have the newline embedded in it, which will mis-format your replacements. The chomp() function removes a trailing newline if one is present. while ( my $line = <WIN> ) { chomp $line;

Since each line has exactly two fields, you should name them. You can split() any extra fields into a generic array, to help find any future problems with the file formatting. my ($lookup_code, $icd_code_and_text, @rest) = split /\t/, $line; warn "Extra tab in file '$icd_file at line $.\n" if @rest;

When you need to inspect more than a single simple variable, use Data::Dumper. In fact, use it to inspect even single simple variables, too. # This "use" line goes at the top, just after "use warnings". use Data::Dumper; $Data::Dumper::Useqq=1;

print Dumper \@columns;
Also, your closing brace is not lined up with the 'f' in 'foreach'. The Perl compiler does not care, but alignment will help any human trying to read your code.

No. This is nonsense. It would only make sense if you had a file with a single line, which contained all the keys and values separated by spaces.
Instead of a hash, we need an array (declared, of course). my @cols = split / /, $line;

The == operator compares two vars *numerically*. The eq operator compares two vars as strings, so it is the one you want. In other words, "3" == "3.0", but "3" ne "3.0".
Also, if you have just determined that $val is an exact match, then s/// is overkill; just replace $var by assigning to it. if ( $val eq $columns[0] ) { $val = $columns[1];Note that, even with those changes, this code will not work, because @columns does not contain the whole table of ICD translations. Even if it did contain them, you would need *two* loops, nested, for this method to work. That would be needlessly complex and inefficient. Later, we will use a simple hash instead of @columns and two loops.

This looks confused. print IN $anything_at_all will write to the IN file. Are you trying to overwrite the data in 'female1.txt'? Luckily, Perl will not let you, because you opened the file as read-only. Your original description says "...should be replaced with ICD-code files corresponding...", but you are not outputting the entire line. Is the '>>' a debugging marker, or does it indicate that you are trying to append to a file? Going by your original description, I think you need: print join( ' ', @columns ), "\n";

The problem with your *approach* is just the failure to preserve the ICD data from the first half of the program so that the second half can use it. This can be done by declaring %lookup_icd above the first while() loop, and then within the while() loop, use: $lookup_icd{$icd_code} = $icd_code_and_text;

This looks confused. print IN $anything_at_all will write to the IN file. Are you trying to overwrite the data in 'female1.txt'? Luckily, Perl will not let you, because you opened the file as read-only. Your original description says "...should be replaced with ICD-code files corresponding...", but you are not outputting the entire line. Is the '>>' a debugging marker, or does it indicate that you are trying to append to a file? Going by your original description, I think you need:

I need to overwrite the result in 'female1.txt' instead of writing in a new output file

.

can that be achieved by changing the 'female1.txt' in to read and write mode

print {$out_fh} join( ' ', @cols ), "\n"

to

print {$in_path} join( ' ', @cols ), "\n"

Let me know if there is any other way to do this. thanks for your help in advance. your explanations are really good. I appreciate your time and effort for helping

Yes, it could be achieved by opening the file in read+write mode, or by re-opening the file in write mode after its read-only filehandle was closed. However, either of these methods would require other code changes, to hold all the lines of output until after all the input had occurred.
The simplest way is to append this code to the bottom of my previous code: