31

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?

Aashu
  • 771

5 Answers5

41

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.

  • 6
    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 07 '18 at 09:28
11

Try this awk one-liner,

$ awk 'END{ var=FILENAME; split (var,a,/\//); print a[5]}' /home/abc/imp/asgd.csv
asgd.csv
Avinash Raj
  • 3,703
9

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
  • 1
    This should be top answer. It's much safer to get basename command than to split by slashes and hope that there is no \/ in the filename – Karel Bílek Mar 16 '20 at 11:59
2

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
CodeGnome
  • 7,820
-1

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 
aze2201
  • 109