Как изменить значения импортированной переменной 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

person Hugo    schedule 14.07.2021    source источник
comment
Изменить $Animal_Farm.Status[1] = "Employed" на $Animal_Farm[1].Status = "Employed"   -  person Mathias R. Jessen    schedule 14.07.2021


Ответы (2)


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

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

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

$Animal_Farm[1].Status
person Mathias R. Jessen    schedule 14.07.2021

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

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

Эта функция, которая также работает с методами, называется перечисление членов и более подробно объясняется в < href="https://stackoverflow.com/a/44620191/45375">этот ответ.

Перечисление членов не поддерживает назначение свойствам, однако:

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

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

Если вы попытались присвоить значение свойства с помощью индексирования ([...]) в массив значений, полученных с помощью перечисления членов ($Animal_Farm.Status), например. $Animal_Farm.Status[1] = "Employed", это назначение тихо игнорируется.

  • Причина в том, что $Animal_Farm.Status возвращает массив значений свойств, которые больше не связаны с объектами, из которых они получены, и хотя технически вы можете изменить этот массив, назначив его элементам , измененный массив просто отбрасывается после оператора присваивания, учитывая, что он нигде не фиксируется.
    Короче говоря: Вы по ошибке изменяете временный массив< /эм>.

  • Напротив, применение индекса к самой коллекции ($Animal_Farm[1] для возврата второго объекта, хранящегося в коллекции) возвращает ссылку на объект, .Status свойство которой можно эффективно изменить ($Animal_Farm[1].Status = "Employed" )


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

# 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 issue #6802 для обсуждения из-за этого, возможно, удивительного поведения.

person mklement0    schedule 14.07.2021