Я думаю, ваша основная проблема в том, что вы пытались использовать синтаксис bash в сценарии sh. Bash определяет расширения для общего знаменателя sh; если вы хотите использовать специфические для bash функции, ваш сценарий должен начинаться с #!/bin/bash
, а не с #!/bin/sh
. В
Sh нет синтаксиса ((...))
для арифметических выражений. Но он здесь и не нужен, вы можете использовать переносимый [ ... ]
условный синтаксис. В условном [ ... ]
оператор "меньше чем" записывается -lt
.
Скобки {1..2}
- еще одна особенность bash, которой нет в sh. Еще одна ошибка в вашем скрипте - X=$A+1
, который устанавливает X
в строку вида 42+1
, если значение A
равно 42
; чтобы выполнить арифметическое вычисление, нужно использовать синтаксис арифметического выражения $((...))
.
Также, в качестве общего замечания, всегда используйте двойные кавычки вокруг подстановок переменных.
Еще одна проблема с вашим кодом заключается в том, что он выглядит так, будто A
- десятичное число. Арифметика Shell работает только с целыми числами. Я адаптировал алгоритм, но проверьте, что он делает, возможно, я округлил не так, как вы задумали. Использовать awk только для подсчета количества строк - излишество, wc -l
- более понятный и быстрый способ сделать это. Аналогично, чтобы вывести первые N строк файла, просто вызовите head
.
Еще одна ошибка заключается в том, что $i_chunk
- это значение переменной i_chunk
. Чтобы взять значение i
и добавить _chunk
, нужно разделить имя переменной скобками: ${i}_chunk
.
Я понятия не имею, что должен делать цикл на j
, я оставил его в покое.
#!/bin/sh
for i in 1 2
do
input="../ExpressionSet_${i}_chunk.txt"
for j in 1 2
do
A=$(wc -l <"$input")
Y=100
X=0
if [ "$A" -lt "$Y" ]; then
X=$((A+100))
else
X=$A
fi
head -n "$((X/100))" "$input" > "$i"_top1pc.txt
head -n "$((X/20))" "$input" > "$i"_top5pc.txt
done
done
Если вы решите написать сценарий на bash, вы можете использовать несколько возможностей bash:
((...))
для арифметических оценок (но все еще только целочисленных)typeset -i
для объявления целочисленной переменной, так что присвоение арифметического выражения оценивает ее#!/bin/bash
for i in 1 2
do
input="../ExpressionSet_${i}_chunk.txt"
for j in 1 2
do
A=$(wc -l <"$input")
Y=100
typeset -i X
if ((A < Y)); then
X=A+100
else
X=$A
fi
head -n "$((X/100))" "$input" > "$i"_top1pc.txt
head -n "$((X/20))" "$input" > "$i"_top5pc.txt
done
done
С sed
:
sed -E 's/(jvmRoute=)([a-zA-Z0-9"-])+/\1"VALUE10"/g'
Поскольку вы не указали, каким может быть исходное значение jvmRoute
, я написал регулярное выражение для приведенного выше примера, но вы можете настроить его для своего потребности.
Чтобы заменить непосредственно в файле, используйте:
sed -i -E 's/(jvmRoute=)([a-zA-Z0-9"-])+/\1"VALUE10"/g' server.xml
Но использование синтаксического анализатора xml было бы лучшим способом, вероятно.
У вас нет строк, начинающихся с "jvmRoute". (^
означает начало строки, просто опустив это, вы должны изменить два вхождения в вашем файле.)
sed 's/patternFrom/patternTo/' file.txt
• "s/" означает замену того, что следует далее: эту замену теперь нужно применить к нашему файлу, путем ввод однострочной команды:
• Команды могут применяться с помощью sed только к выбранному набору строк. Эти линии идентифицируются по их порядковому номеру внутри файла, начиная со строки 1.
Например:
sed '2s/patternFrom/patternTo' file.txt
• выполняет подстановку только во второй строке
или
sed '2,$s/patternFrom/patternTo' file.txt
• выполняет подстановку со 2 строки до последней, обозначенной специальным символом «$».
Даже больше
• sed содержит внутренний буфер, называемый пространством хранения. Этот буфер можно активировать определенными командами, например 'g'. Команда 'g' приводит к замене пробела текущую строку ввода, чтобы совпадения можно было повторить в строке ввода
В вашем случае попробуйте сопоставить все вхождения во всех строках с помощью:
sed 's/patternFrom/patternTo/g' file.txt
Я думаю, что не работает шаблон
Убедитесь, что регулярное выражение работает, попробуйте с
sed 's/jvmRoute="[a-zA-Z0-9-\.]*["]/jvmRoute="VALUE10"/g
Ваша команда sed
ничего не изменит, поскольку в вашем файле нет строки, начинающейся со строки jvmRoute
.
Синтаксический анализ XML должен выполняться с помощью анализатора XML.
XMLStarlet — хорошая команда, -синтаксический анализатор строк:
$ xml ed -u '//Engine/@jvmRoute' -v 'VALUE10' server.xml >server-new.xml
Это изменит значение атрибута jvmRoute
всех узлов Engine
на строку VALUE10
и сохранит полученный XML в server-new.xml
.
Чтобы изменить значение только для узла Engine
, который имеетdefaultHost="localhost"
:
xml ed -u '//Engine[@defaultHost="localhost"]/@jvmRoute' -v 'VALUE10' server.xml >server-new.xml
XMLStarlet доступен по адресу http://xmlstar.sourceforge.net/, но сначала проверьте свой менеджер пакетов. Иногда исполняемый файл XMLStarlet называется xmlstarlet
, а не xml
.