Как изменить значения импортированной переменной CSV с помощью PowerShell

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

      $Animal_Farm = Import-CSV "Test.csv"

Echo "The Data"
$Animal_Farm

Echo "`n`n`n"

Echo "Dog's Status"
$Animal_Farm.Status[1]
Echo "`n`n`n"

Echo "Updating Dog's Status to Employed"
$Animal_Farm.Status[1] = "Employed"
Echo "`n`n`n"

Echo "Dog's Status"
$Animal_Farm.Status[1]

Это выходные данные, данные не изменились, а статус Dog по-прежнему Redundant.

      The Data

Animal Ocupation    Status   
------ ---------    ------   
Cat    Construction Employed 
Dog    Professional Redundant
Rat    GP           Employed 




Dog's Status
Redundant




Updating Dog's Status to Employed




Dog's Status
Redundant

Как редактировать импортированные данные? Мой план состоит в том, чтобы передать измененные данные в файл JSON.

Это содержимое файла CSV

      Animal,Ocupation,Status
Cat,Construction,Employed
Dog,Professional,Redundant
Rat,GP,Employed

2 ответа

содержит массив объектов, каждый из которых имеет свойство.

Когда вы просите PowerShell разрешить $Animal_Farm.Status, PowerShell говорит: «Да, у массива нет свойства, позвольте мне создать новый массив из Statusзначения свойств каждого элемента в массиве», что вы в конечном итоге индексируете с помощью $Animal_Farm.Status[1].

Чтобы обратиться к свойствам одного из базовых элементов в исходном массиве, используйте оператор индекса непосредственно на $Animal_Farmвместо:

      $Animal_Farm[1].Status

Чтобы дополнить полезный ответ Матиаса Р. Джессена концептуальной информацией:

Как утверждает Матиас, доступ к свойству () в коллекции (массиве) объектов () автоматически возвращает значения свойств элементов коллекции в массиве [1] (при условии, что коллекция сама по себе не имеет свойства с таким именем, в в этом случае последний имеет приоритет).

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

Однако перечисление элементов не поддерживает присвоение свойств :

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

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

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

  • Причина в том, что возвращает массив значений свойств , которые больше не связаны с объектами, из которых они были получены , и хотя вы можете технически изменить этот массив, присваивая его элементам, измененный массив просто отбрасывается после оператора присваивания, учитывая, что он не захвачен в любом месте.
    Вкратце: вы по ошибке изменяете временный массив .

  • Напротив, применение индекса к самой коллекции ( для возврата второго объекта , хранящегося в коллекции) возвращает ссылку на объект , свойство, которое вы затем можете эффективно изменить ( )


Упрощенный пример :

      # Create a 2-element sample array.
$animals = [pscustomobject] @{ Animal = 'Cat'; Status = 'Employed' },
           [pscustomobject] @{ Animal = 'Dog'; Status = 'Redundant' } 


# Trying to set the status of ALL animals via member enumeration
# CAUSES AN ERROR, because it isn't supported:
#     InvalidOperation: The property 'Status' cannot be found on this object. [...]
$animals.Status = 'Employed'    # !! ERROR


# Trying to set the status of ONE animal via member enumeration is
# QUIETLY IGNORED:
#  * What is being modified is a *temporary array* of property values.
#  * Therefore, $animals.Status[1] is still 'Redundant' after this statement.
$animals.Status[1] = 'Employed' # !! QUIETLY IGNORED

# OK: Avoid member enumeration, and index directly into the collection
#     to get the animal object of interest, then set its property:
$animals[1].Status = 'Employed' # OK

[1] Технически массив значений возвращается только в том случае, если входная коллекция состоит из двух или более элементов; для одноэлементной коллекции значение свойства одного элемента возвращается как есть. Другими словами: перечисление членов ведет себя как конвейер PowerShell ; см. этот ответ и этот ответ для примеров связанных ловушек и выпуск GitHub № 6802 для обсуждения этого, возможно, удивительного поведения.

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