19

I have an awk script and I have passed a CSV file to it.

awk -f script.awk /home/abc/imp/asgd.csv

What am I doing is to get FILENAME within script.awk. FILENAME gives me the whole path. As I am in awk I cannot use basename FILENAME.

print FILENAME;
/home/abc/imp/asgd.csv

I have tried with this within script.awk

echo $FILENAME | awk -F"/" '{print $NF}'

but I cannot execute this within script.awk. How can I get asgd.csv within an awk program?

29

Several options:

awk '
  function basename(file) {
    sub(".*/", "", file)
    return file
  }
  {print FILENAME, basename(FILENAME)}' /path/to/file

Or:

awk '
  function basename(file, a, n) {
    n = split(file, a, "/")
    return a[n]
  }
  {print FILENAME, basename(FILENAME)}' /path/to/file

Note that those implementations of basename should work for the common cases, but not in corner cases like basename /path/to/x/// where they return the empty string instead of x or / where they return the empty string instead of /, though for regular files, that should not happen.

The first one will not work properly if the file paths (up to the last /) contain sequences of bytes that don't form valid characters in the current locale (typically this kind of thing happens in UTF-8 locales with filenames encoded in some 8 bit single byte character set). You can work around that by fixing the locale to C where every sequence of byte form valid characters.

  • 3
    If you need code that will work easily within an existing awk script without introducing a function, you should use: n = split(FILENAME, a, "/"); basename=a[n];. Don't use sub as that will actually change the FILENAME variable (which is a non-issue with the function since awk uses call by value). – shiri Jan 7 '18 at 9:28
9

Try this awk one-liner,

$ awk 'END{ var=FILENAME; split (var,a,/\//); print a[5]}' /home/abc/imp/asgd.csv
asgd.csv
  • 3
    or awk 'END{ var=FILENAME; n=split (var,a,/\//); print a[n]}' /home/abc/imp/asgd.csv – Avinash Raj Jun 3 '14 at 8:39
0

the best way to export it from input CSV or directly from input file path you can reverse it , then get 1 column and then again reverse it.

function getFileFromPath() {
    FileName=$1
    cat $FileName | while read Filename
    do
        echo $Filename| rev | awk -v FS='/' '{print $1}' | rev 
    done
}

or simply

echo $FileNamePath| rev | awk -v FS='/' '{print $1}' | rev 
0

Use Awk's Split Function

One way to do this is to use the split function. For example:

awk '{idx = split(FILENAME, parts, "/"); print parts[idx]; nextfile}' /path/to/file

This even works on multiple files. For example:

$ awk '{idx = split(FILENAME, parts, "/"); print parts[idx]; nextfile}' \
      /etc/passwd /etc/group
passwd
group
0

On the systems where basename command is available, one could use awk's system() function or expression | getline var structure to call external basename command. This can help accounting for corner cases mentioned in Stephane's answer.

$ awk '{cmd=sprintf("basename %s",FILENAME);cmd | getline out; print FILENAME,out; exit}' /etc///passwd
/etc///passwd passwd

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.