Добавить имя файла в качестве нового столбца с помощью awk

Прежде всего, существующие вопросы не решили мою проблему, поэтому я спрашиваю снова.

У меня есть два текстовых файла temp.txt

adam    12
george  15
thomas  20

и демо.txt

mark    8
richard 11
james   18

Я хочу объединить их и добавить третий столбец в качестве имен файлов без расширения, например:

adam    12   temp
george  15   temp
thomas  20   temp
mark    8    demo
richard 11   demo
james   18   demo

Я использовал этот скрипт:

for i in $(ls); do name=$(basename -s .txt $i)| awk '{OFS = "\t";print $0, $name} ' $i; done

Но это дает следующую таблицу:

mark    8   mark    8
richard 11  richard 11
james   18  james   18
adam    12  adam    12
george  15  george  15
thomas  20  thomas  20

Я не понимаю, почему он дает переменную имени как всю таблицу.

Заранее спасибо.

скопируйте / вставьте свой сценарий оболочки в shellcheck.net и исправьте проблемы, о которых он вам говорит.

Ed Morton 07.01.2023 16:58

взгляните на переменную awk FILENAME

kvantour 07.01.2023 22:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
76
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Awk не имеет доступа к переменным Bash и наоборот. Внутри скрипта Awk name не определено, поэтому $name интерпретируется как $0.

Кроме того, не используйте ls в скриптах, и цитируйте свои переменные оболочки.

Наконец, присваивание name ничего не печатает, поэтому передача его вывода в Awk не имеет смысла.

for i in ./*; do
    name=$(basename -s .txt "$i")
    awk -v name = "$name" '{OFS = "\t";print $0, $name}' "$i"
done

Таким образом, вычисление basename можно легко выполнить в Awk, но я оставлю это в качестве упражнения. (Подсказка: sub(regex, "", FILENAME))

Ответ принят как подходящий

Во-первых, вам нужно размаскировать $name, который находится внутри одинарных кавычек, поэтому он не заменяется именем файла из оболочки. После этого вам нужно добавить двойные кавычки вокруг $name, чтобы awk увидел это как строку:

for i in $(ls); do name=$(basename -s .txt $i); awk '{OFS = "\t";print $0, "'$name'"} ' $i; done

Это потерпит неудачу особым образом, если имена файлов содержат кавычки, точки с запятой, пробелы и т. д.

tripleee 07.01.2023 16:15

Это содержит несколько анти-шаблонов и дополнительные неэффективности.

Ed Morton 07.01.2023 18:11

awk имеет переменную FILENAME, значением которой является путь к обрабатываемому файлу, и переменную FNR, значением которой является номер текущей строки в файле; поэтому в FNR == 1 вы можете обработать FILENAME и сохранить результат в переменной, которую вы будете использовать впоследствии:

awk -v OFS='\t' '
    FNR == 1 {
        basename = FILENAME
        sub(".*/", "", basename)      # strip from the start up to the last "/"
        sub(/\.[^.]*$/, "", basename) # strip from the last "." up to the end
    }
    { print $0, basename }
' ./path/temp.txt ./path/demo.txt
adam    12   temp
george  15   temp
thomas  20   temp
mark    8    demo
richard 11   demo
james   18   demo

Использование BASH:

for i in temp.txt demo.txt ; do  while read -r a b ; do printf "%s\t%s\t%s\n" "$a" "$b" "${i%%.*}" ; done <"$i" ; done

Выход:

adam    12  temp
george  15  temp
thomas  20  temp
mark    8   demo
richard 11  demo
james   18  demo

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

Другие вопросы по теме