Как добавить статический контент в одну ячейку существующего файла CSV

Предположим, мне нужно добавить приведенное ниже содержимое в первую ячейку (а не построчно) существующего файла CSV, содержащего сведения о клиенте. Как я могу этого достичь?

Добавляемый контент:

"This is Loganayaki ,she is trying to append the csv file

But she is not able to, she is facing difficulty using shell script

she is seeking help to fix this issue, so that she cab complete her task.
she tried few things which is not helping her"

Customer_File:

ID,Customer_Name,Cust_ADD
1,A,CBE
2,B,POL
3,C,POL

Я попробовал приведенный ниже код

#!/bin/bash

# File paths

csv_file = "data.csv"

# New content to prepend

new_content = "This is Loganayaki ,she is trying to append the csv file

But she is not able to, she is facing difficulty using shell script

she is seeking help to fix this issue, so that she cab complete her task.
she tried few things which is not helping her"

# Read existing content of the CSV file (excluding the first line)

existing_content=$(tail -n +2 "$csv_file")

# Combine new content with existing content

combined_content = "$new_content"$'\n'"$existing_content"

# Write the combined content back to the CSV file

echo "$combined_content" > "$csv_file"

Он добавляется, но new_content добавляется в три разные строки, а \n оказывается пустой строкой.

Мое ожидание

    This is Loganayaki ,she is trying to append the csv file
    
    But she is not able to, she is facing difficulty using shell script
    
    she is seeking help to fix this issue, so that she cab complete her task.
    she tried few things which is not helping her
    
   
   
   ID,Customer_Name,Cust_ADD
    1,A,CBE
    2,B,POL
    3,C,POL

Используйте язык с более надежными возможностями анализа CSV. Например, в Python есть модуль csv для чтения и записи файлов csv. Это значительно облегчит вашу задачу.

larsks 25.07.2024 05:05

есть ли ссылка, я могу сослаться на

Loganayaki mahalingam 25.07.2024 05:09

Я имею в виду... вот ссылка, которую я дал в предыдущем комментарии.

larsks 25.07.2024 05:09

Просто чтобы уточнить: вы просто хотите добавить строку в первые строки CSV-файла? Судя по ожидаемому результату, это так и есть.

tax evader 25.07.2024 05:21

Я думаю, вы можете добиться ожидаемого результата, заменив tail -n +2 "$csv_file" просто на cat "$csv_file", что даст combined_content = "$new_content"$'\n\n\n'$(cat "$csv_file")

tax evader 25.07.2024 05:24

Правильно, я хочу добавить строку в первую ячейку файла csv.

Loganayaki mahalingam 25.07.2024 05:41

@larsks К вашему сведению, некоторые варианты awk (например, GNU и Kernighans awk) имеют встроенный синтаксический анализ CSV, см. «Какой самый надежный способ эффективного анализа CSV с использованием awk»‌, но OP Вопрос на самом деле, похоже, не имеет ничего общего с CSV, речь идет просто о прикреплении содержимого переменной в верхней части файла (который может быть CSV, но может быть чем-то другим).

Ed Morton 25.07.2024 12:49

Просто заключите $new_content в «двойные кавычки», так как в вашей строке они не используются. Попробуйте просто: { printf '"%s"\n" "$new_content";cat "$csvFile";} >outfile.csv или printf '"%s"\n%s\n' "$new_content" "$(<$csvFile)" >outfile.csv....

F. Hauri - Give Up GitHub 25.07.2024 13:21

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

user1934428 25.07.2024 13:54

... Или более многоразовые: printf '"%s"\n%s\n' "${new_content//\"/\"\"}" "$(<$csvFile)" >outfile.csv;.

F. Hauri - Give Up GitHub 25.07.2024 14:08
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
116
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Я думаю, что если он просто добавляется к первым строкам файла csv, вам просто нужно заменить existing_content=$(tail -n +2 "$csv_file") на existing_content=$(cat "$csv_file"), так как вы хотите сохранить все исходное содержимое файла.

#!/bin/bash

# File paths

csv_file = "data.csv"

# New content to prepend

new_content = "This is Loganayaki ,she is trying to append the csv file

But she is not able to, she is facing difficulty using shell script

she is seeking help to fix this issue, so that she cab complete her task.
she tried few things which is not helping her"

# Read existing content of the CSV file (excluding the first line)

existing_content=$(cat "$csv_file")

# Combine new content with existing content

combined_content = "$new_content"$'\n\n\n'"$existing_content"

# Write the combined content back to the CSV file

echo "$combined_content" > "$csv_file"

Это отредактирует файл так, чтобы он был

This is Loganayaki ,she is trying to append the csv file

But she is not able to, she is facing difficulty using shell script

she is seeking help to fix this issue, so that she cab complete her task.
she tried few things which is not helping her


ID,Customer_Name,Cust_ADD
1,A,CBE
2,B,POL
3,C,POL

Однако это недопустимый вывод CSV.

tripleee 25.07.2024 06:47

@tripleee: Полученный файл больше не должен быть действительным CSV. Посмотрите на ожидаемый результат, как указано в вопросе.

user1934428 25.07.2024 11:14

Результат, который вы описываете в «Мое ожидание...», может быть достигнут с помощью

if tf=$(mktemp)
then
  printf %s "$new_content" >$tf
  cat "$csv_file" >>$tf
  mv -- "$tf" "$csv_file"
fi

Или — адаптируя идею @EdMorton:

if tf=$(mktemp)
then
  {
    printf %s "$new_content"
    cat "$csv_file"
  } >$tf
  mv -- "$tf" "$csv_file"
fi

Конечно, файл CSV больше не будет действительным CSV, как упомянул @tripleee в своем комментарии, но это то, о чем вы просили.

Как отмечено в комментариях, ваш ожидаемый результат не соответствует вашему прозаическому описанию того, что вы хотите. Я предполагаю, что это связано с ограниченным пониманием формата CSV; и поэтому я предложу несколько альтернативных решений, которые позволят достичь того, чего, как я полагаю, вы действительно хотите.

Вкратце: чтобы текстовый файл был действительным файлом CSV, он должен удовлетворять нескольким простым ограничениям.

  • Каждая запись должна содержать одинаковое количество полей (обычно строка является записью; но поскольку поле может содержать символы новой строки, это не совсем так).
  • Любое поле, содержащее буквальную кавычку, символ новой строки или разделитель, должно быть заключено в кавычки. (По определению разделителем является запятая ,, но существует множество распространенных вариантов, таких как TSV, где вместо этого разделителем является символ табуляции, а также варианты, разделенные точкой с запятой, вертикальной чертой и т. д.) Другие поля также могут быть заключены в кавычки, но это совершенно необязательно. Чтобы закодировать буквальный символ-разделитель внутри поля в кавычках, удвойте его.

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

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

(Чтобы упростить следующее изложение, я буду использовать более короткое значение, чем то, которое вам нужно. Мы добавим поле

foo, "bar"
baz!

Вы заметите, что он содержит буквальную запятую, буквальные кавычки и буквальную новую строку.)

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

ID,Customer_Name,Cust_ADD
"1foo, ""bar""
baz!",A,CBE
2,B,POL
3,C,POL

Если вы хотите заменить, а не добавить, очевидно, удалите 1, который был старым значением этой ячейки. Чтобы добавить (или заменить) имя первого поля в строке заголовка, должно быть очевидно, что нужно изменить (т. е. выбрать первую строку вместо второй).

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

#!/bin/bash

csv_file = "data.csv"

new_content = "This is Loganayaki ,she is trying to append the csv file

But she is not able to, she is facing difficulty using shell script

she is seeking help to fix this issue, so that she cab complete her task.
she tried few things which is not helping her"

# Apply necessary transformations
replacement=${new_content//\"/\"\"}
replacement=${replacement//$'\n'/$'\\\n'}

# Replace
sed -i "2s/\([^,]*\),/\"\1$replacement\",/" "$csv_file"

Простой скрипт sed заменяет первое поле и запятую после него во второй строке на открывающую кавычку, предыдущее значение (\1), новый текст, закрывающую кавычку и запятую, эффективно добавляя новый текст к существующему значению. в первой ячейке этой строки.

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

sed -i "2s/^[^,]*,/$replacement,/" "$csv_file"

И, как отмечалось выше, если вы хотите настроить таргетинг на другую строку, отличную от второй, измените адрес номера строки 2.

Демо: https://ideone.com/5o54dE

Это довольно хрупко, потому что

  • Он не будет работать, если текст замены будет содержать косую черту. Вы можете изменить сценарий sed, чтобы использовать другой разделитель, или выполнить другое преобразование, чтобы добавить обратную косую черту перед каждой буквальной косой чертой. На самом деле, вам нужно сделать это для каждой буквальной обратной косой черты или амперсанда.

    replacement=${replacement//[\\/&]/\\&}
    

    При этом используется расширение параметра Bash , которое не переносимо на sh (тогда как исходный скрипт не использовал синтаксис Bash и, таким образом, вполне мог иметь #!/bin/sh shebang . Возможно, см. также Разница между sh и ругайся)

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

  • Это может привести к необычным поломкам, если существующее поле уже заключено в кавычки. Для этой цели было бы несложно написать немного другое регулярное выражение. (Например, разрешите закрывающую кавычку непосредственно перед запятой и в этом случае опустите начальную кавычку из нового значения. Регулярное выражение должно допускать двойные двойные кавычки или любые символы, которые не являются двойными кавычками, в первом поле. Если вы хотите чтобы реализовать обе возможности, сценарий должен быть немного сложнее, хотя и ненамного.)

Некоторые из вышеперечисленных уродств проистекают из неудачной границы интерфейса между оболочкой и sed. Вы часто видите скрипты sed, собранные из строковых переменных оболочки, но это приводит ко многим проблемам, когда вам нужно различными способами массировать строки, чтобы сделать их подходящими для sed. Учитывая это, для сценариев Awk доступен гораздо более понятный интерфейс; но стандартный Awk не имеет удобного редактирования sed -i на месте (что тоже не является стандартным, но довольно распространено). Тогда вам просто нужно записать временный файл и переименовать его, чтобы заменить входной файл. Кроме того, синтаксис Awk более подробный (но и менее предназначен только для записи).

t=$(mktemp -t replace.XXXXXXXX) || exit
trap 'rm -f "$t"; exit' ERR EXIT HUP INT
awk -F , -v replace = "$new_content" '
BEGIN { OFS=FS; gsub(/"/, "\"\"", replace) }
FNR==2 { $1 = "\"" $1 replace "\"" } 1' "$csv_file" >"$t" &&
mv "$t" "$csv_file"

Демо: https://ideone.com/DoPH8x

Это потребует более обширного рефакторинга, чтобы правильно обрабатывать цитируемые поля во входных данных.

Однако на этом этапе вместо того, чтобы усложнять сценарий sed или Awk, возможно, стоит обратиться к Python, чей модуль csv сделает за вас все это и многое другое.

import csv
import sys
 
 
csv_file = "data.csv"
 
new_content = """This is Loganayaki ,she is trying to append the csv file
 
But she is not able to, she is facing difficulty using shell script
 
she is seeking help to fix this issue, so that she cab complete her task.
she tried few things which is not helping her"""
 
with open(csv_file) as inp:
    rows = csv.reader(inp)
    writer = csv.writer(sys.stdout)
    for lineno, row in enumerate(rows, 1):
        if lineno == 2:
            row[0] += new_content
        writer.writerow(row)

Демо: https://ideone.com/dSp7DK

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

Не пытайтесь прочитать весь входной файл в памяти, просто используйте временный файл:

#!/usr/bin/env bash

tmp=$(mktemp) &&
trap 'rm -f "$tmp"; exit' EXIT &&
{
    printf '%s' "$new_content" &&
    cat -- "$csv_file"
} > "$tmp" &&
mv -- "$tmp" "$csv_file"

Символы && необходимы, чтобы не испортить входной файл, если на предыдущем шаге что-то не удалось. Если вас беспокоит сохранение разрешений и т. д. исходного файла, измените mv -- "$tmp" "$csv_file" на cat -- "$tmp" > "$csv_file".

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