#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
$