Это действительно просто объяснение ответа Юзема , но я не чувствовал, что такое большое редактирование следует делать кому-то другому, а комментарии не позволяют форматировать, так что ...
rdom () { local IFS=\> ; read -d \< E C ;}
Давайте назовем это «read_dom» вместо «rdom», поместим его немного в пространство и используем более длинные переменные:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
}
Хорошо, поэтому он определяет функцию с именем read_dom. Первая строка делает IFS (разделитель поля ввода) локальным для этой функции и изменяет его на>. Это означает, что когда вы читаете данные вместо того, чтобы автоматически разделяться на пробелы, символы табуляции или перевода строки, они разделяются на «>». В следующей строке написано, что нужно читать ввод из stdin, и вместо того, чтобы останавливаться на новой строке, останавливаться, когда вы видите символ «<» (флаг -d для deliminator). То, что читается, затем разделяется с использованием IFS и присваивается переменной ENTITY и CONTENT. Поэтому возьмите следующее: </p>
<tag>value</tag>
При первом вызове read_dom
получается пустая строка (так как '<' - первый символ). Это делится IFS на просто '', так как нет символа '>'. Read затем назначает пустую строку обеим переменным. Второй вызов получает строку «тег> значение». Затем IFS разделяется на два поля: «тег» и «значение». Read затем присваивает переменные, такие как: ENTITY=tag
и CONTENT=value
. Третий вызов получает строку '/ tag>'. Это разделено IFS на два поля '/ tag' и ''. Read затем назначает переменные, такие как: ENTITY=/tag
и CONTENT=
. Четвертый вызов вернет ненулевой статус, потому что мы достигли конца файла.
Теперь его цикл while очищен, чтобы соответствовать приведенному выше:
while read_dom; do
if [[ $ENTITY = "title" ]]; then
echo $CONTENT
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
В первой строке просто сказано: «пока функция read_dom возвращает нулевой статус, сделайте следующее». Вторая строка проверяет, является ли объект, который мы только что видели, «заголовком». Следующая строка повторяет содержание тега. Четыре линии выхода. Если это не заголовок, цикл повторяется в шестой строке. Мы перенаправляем «xhtmlfile.xhtml» в стандартный ввод (для функции read_dom
) и перенаправляем стандартный вывод в «titleOfXHTMLPage.txt» (эхо из более раннего цикла).
Теперь с учетом следующего (аналогично тому, что вы получаете при перечислении сегмента на S3) для input.xml
:
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>sth-items</Name>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>item-apple-iso@2x.png</Key>
<LastModified>2011-07-25T22:23:04.000Z</LastModified>
<ETag>"0032a28286680abee71aed5d059c6a09"</ETag>
<Size>1785</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
и следующий цикл:
while read_dom; do
echo "$ENTITY => $CONTENT"
done < input.xml
Вы должны получить:
=>
ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/" =>
Name => sth-items
/Name =>
IsTruncated => false
/IsTruncated =>
Contents =>
Key => item-apple-iso@2x.png
/Key =>
LastModified => 2011-07-25T22:23:04.000Z
/LastModified =>
ETag => "0032a28286680abee71aed5d059c6a09"
/ETag =>
Size => 1785
/Size =>
StorageClass => STANDARD
/StorageClass =>
/Contents =>
Итак, если мы написали цикл while
, как у Юзема:
while read_dom; do
if [[ $ENTITY = "Key" ]] ; then
echo $CONTENT
fi
done < input.xml
Мы получили бы список всех файлов в корзине S3.
EDIT
Если по какой-то причине local IFS=\>
не работает для вас, и вы установили его глобально, вы должны сбросить его в конце функции, например:
read_dom () {
ORIGINAL_IFS=$IFS
IFS=\>
read -d \< ENTITY CONTENT
IFS=$ORIGINAL_IFS
}
В противном случае любое разбиение строки, которое вы сделаете позже в скрипте, будет испорчено.
РЕДАКТИРОВАТЬ 2
Чтобы разделить пары имя / значение атрибута, вы можете увеличить read_dom()
следующим образом:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local ret=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $ret
}
Затем напишите свою функцию для анализа и получите нужные данные, например:
parse_dom () {
if [[ $TAG_NAME = "foo" ]] ; then
eval local $ATTRIBUTES
echo "foo size is: $size"
elif [[ $TAG_NAME = "bar" ]] ; then
eval local $ATTRIBUTES
echo "bar type is: $type"
fi
}
Тогда, пока вы read_dom
звоните parse_dom
:
while read_dom; do
parse_dom
done
Затем приведен следующий пример разметки:
<example>
<bar size="bar_size" type="metal">bars content</bar>
<foo size="1789" type="unknown">foos content</foo>
</example>
Вы должны получить этот вывод:
$ cat example.xml | ./bash_xml.sh
bar type is: metal
foo size is: 1789
РЕДАКТИРОВАТЬ 3 другой пользователь сказал, что у него проблемы с ним во FreeBSD, и предложил сохранить состояние выхода из чтения и вернуть его в конце read_dom, например:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local RET=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $RET
}
Я не вижу причин, почему это не должно работать