Как удалить путь из переменной входного имени файла awk — доступно ли каким-либо образом базовое имя?

#bash #awk

#bash #awk

Вопрос:

Следующая команда

 gawk '{print $0, FILENAME}' input.txt > result.txt
  

где input.txt является ли:

 FIXED3 LENGTH7      FILE FORMAT     00001
FIXED2 LENGTH8      FILE FORMAT     00002
FIXED2 LENGTH20     FILE FORMAT     00003
FIXED1 LENGTH20     FILE FORMAT     00004
  

Выдает следующий желаемый результат:

 FIXED3 LENGTH7      FILE FORMAT     00001 input.txt
FIXED2 LENGTH8      FILE FORMAT     00002 input.txt
FIXED2 LENGTH20     FILE FORMAT     00003 input.txt
FIXED1 LENGTH20     FILE FORMAT     00004 input.txt
  

Однако, если использовать путь к файлу, как показано ниже:

 gawk '{print $0, FILENAME}' /cygdrive/c/dev/data/input.txt > result.txt
  

Тогда имя ФАЙЛА, добавляемое к каждой строке, также включает путь. Это то, что я хочу исправить, я хотел бы получить тот же результат, что и в первом сценарии выше.

 FIXED3 LENGTH7      FILE FORMAT     00001 /cygdrive/c/dev/data/input.txt
FIXED2 LENGTH8      FILE FORMAT     00002 /cygdrive/c/dev/data/input.txt
FIXED2 LENGTH20     FILE FORMAT     00003 /cygdrive/c/dev/data/input.txt
FIXED1 LENGTH20     FILE FORMAT     00004 /cygdrive/c/dev/data/input.txt
  

Ответ №1:

Разделите FILENAME с / на массив и выведите последний элемент массива:

 awk '{n=split(FILENAME,array,"/"); print $0, array[n]}' /cygdrive/c/dev/data/input.txt
  

Ответ №2:

Это один из способов:

 $ gawk '{f=FILENAME; sub(/^.*//,"",f); print $0, f}' ../here/file
FIXED3 LENGTH7      FILE FORMAT     00001 file
FIXED2 LENGTH8      FILE FORMAT     00002 file
FIXED2 LENGTH20     FILE FORMAT     00003 file
FIXED1 LENGTH20     FILE FORMAT     00004 file
  

Объяснено:

 $ gawk '{
    f=FILENAME          # copy the filename to f
    sub(/^.*//,"",f)   # process f instead, removeall from beginning to last /
    print $0, f         # etc. etc.
}' ../here/file
  

или поскольку вы упомянули gawk :

 $ gawk '{print $0, gensub(/^.*//,"",1,FILENAME)}' ../here/file
  

Комментарии:

1. Этот подход сработал так же хорошо, как и у Сайруса. Воздерживаюсь от принятия ответа, пока я не поэкспериментирую с каждым. Я поддержал каждый ответ, который до сих пор работал.

Ответ №3:

Небольшая настройка для эффективности и краткости:

 gawk 'FNR==1{f=gensub(".*/","",1,FILENAME)} $(NF 1)=f'
  

Извлекайте filename ( f здесь ) только один раз из каждого файла, выполняя эту часть в первой строке.
И поскольку FILENAME оно не будет пустым, поэтому просто добавьте его в строку, {print $0} будет подразумеваться.

Однако это изменит разделитель выходных данных, если это не один пробел.
Используйте приведенное ниже, если это не то, что вы хотели:

 gawk 'FNR==1{f=gensub(".*/","",1,FILENAME)}{print $0 OFS f}'
  

Комментарии:

1. Второй вариант (с 0 OFS f) вашего ответа — это тот, который работает, как ожидалось, в моем формате файла фиксированной ширины.

2. @Brian Разные ситуации, разные потребности. Рад узнать, что это работает 🙂

Ответ №4:

Не могли бы вы, пожалуйста, попробовать следующее. Он будет запускаться только в первой строке, чтобы получить точное имя входного файла, и не будет запускаться в каждой строке файла.

 awk 'FNR==1{if(FILENAME~///){sub(/.*//,"",FILENAME)}} {print $0,FILENAME}' Input_file
  

Возможные преимущества этого подхода:

1 — НЕ генерируя отредактированное имя файла в каждой строке, получаем is в самой 1-й строке и просто печатаем во всех остальных строках.

2 — НЕ создан держатель массива / памяти, поэтому это должно быть БЫСТРО и для файла огромного размера.

3- Поскольку я просто печатаю его и не создаю какой-либо дополнительный столбец со значениями имени файла, это также сэкономит время во время выполнения этого кода.



РЕДАКТИРОВАТЬ: Просто пришла в голову еще одна мысль, вы могли бы просто перейти к новому каталогу, где присутствует Input_file, и могли бы вернуться в самом code / one liner, например, следующим образом. ИМХО, я надеюсь, что это будет САМЫМ БЫСТРЫМ среди всех других решений, упомянутых здесь (поскольку мы здесь не выполняем никаких манипуляций с данными, и, более того, мы используем ту же команду, которую вы использовали и ранее :))

 cd  /cygdrive/c/dev/data/ amp;amp; awk '{print $0,FILENAME}' input.txt amp;amp; cd -
  

Особенность этой команды в том, что она вернется в ваш исходный каталог, где вы запускаете код, поэтому вам никогда не будет казаться, что вы куда-то перешли 🙂

Комментарии:

1. @anubhava, Привет, Анубхава, сэр, поскольку вы являетесь экспертом (из всех драгоценных камней в SO) в BASH и awk, я думаю, что мое решение для редактирования, которое, я считаю, должно быть хорошим и быстрым по сравнению с разделением ИМЕНИ файла или созданием массива, хотелось бы узнать ваше мнение о том же, когда у вас есть время, пожалуйста. Буду признателен вам, сэр, если вы могли бы сообщить мне свое мнение по этому поводу.

2. @Брайан, не мог бы ты, пожалуйста, проверить мой ответ (когда у тебя будет время), если это полезно для тебя.

Ответ №5:

Другое awk использование / в качестве разделителя

 gawk -F"/"  ' { printf("%s ",$0) ; $0=FILENAME } { print $NF } ' /home/full/path/input.txt
  

с вашими заданными входными данными

 $ cat /cygdrive/c/dev/data/input.txt
FIXED3 LENGTH7      FILE FORMAT     00001
FIXED2 LENGTH8      FILE FORMAT     00002
FIXED2 LENGTH20     FILE FORMAT     00003
FIXED1 LENGTH20     FILE FORMAT     00004

$ gawk -F"/"  ' { printf("%s ",$0) ; $0=FILENAME } { print $NF } ' /cygdrive/c/dev/data/input.txt
FIXED3 LENGTH7      FILE FORMAT     00001 input.txt
FIXED2 LENGTH8      FILE FORMAT     00002 input.txt
FIXED2 LENGTH20     FILE FORMAT     00003 input.txt
FIXED1 LENGTH20     FILE FORMAT     00004 input.txt

$