В сценарии оболочки ...
Как мне захватить стандартный ввод переменной, не убирая завершающие символы новой строки?
Прямо сейчас я попробовал:
var=`cat`
var=`tee`
var=$(tee)
Во всех случаях $var
не будет завершающей новой строки входного потока. Спасибо.
ТАКЖЕ: Если на входе нет завершающего символа новой строки, то решение не должно добавлять его .
ОБНОВЛЕНИЕ В СВЕТЕ ПРИНЯТОГО ОТВЕТА:
Окончательное решение, которое я использовал в своем коде, выглядит следующим образом:
function filter() {
#do lots of sed operations
#see https://github.com/gistya/expandr for full code
}
GIT_INPUT=`cat; echo x`
FILTERED_OUTPUT=$(printf '%s' "$GIT_INPUT" | filter)
FILTERED_OUTPUT=${FILTERED_OUTPUT%x}
printf '%s' "$FILTERED_OUTPUT"
Если вы хотите увидеть полный код, перейдите на страницу github для расширителя , небольшого сценария оболочки с открытым исходным кодом для фильтра ключевых слов git, который я разработал для целей информационной безопасности. В соответствии с правилами, установленными в файлах .gitattributes (которые могут быть специфичными для отрасли) и git config , git направляет каждый файл через сценарий оболочки expandr.sh при каждом входе или выходе из репозитория. (Вот почему было важно сохранить любые завершающие символы новой строки или их отсутствие.) Это позволяет очищать конфиденциальную информацию и менять местами различные наборы специфических для среды значений для тестовой, промежуточной и активной веток.
filter
беретstdin
- бежитsed
. Вы ловитеstdin
в$GIT_INPUT
распечатайте его обратно вstdout
течение трубы кfilter
и поймать егоstdout
в систему,$FILTERED_OUTPUT
а затем распечатать его обратноstdout
. Все 4 линии в нижней части вашего примера выше можно было бы заменить только это:filter
. Здесь не обидно, просто ... ты слишком усердно работаешь. Вам не нужны переменные оболочки большую часть времени - просто направьте ввод в нужное место и передайте его дальше.filter
, то он добавит символы новой строки к концам любых входных потоков, которые изначально не заканчивались символами новой строки. На самом деле я изначально только что сделал,filter
но столкнулся с той проблемой, которая привела меня к этому решению, потому что ни «всегда добавлять новые строки», ни «всегда удалять новые строки» не являются приемлемыми решениями.sed
вероятно, будет делать дополнительную новую строку - но вы должны справиться с этимfilter
не со всеми остальными. И все те функции, которые у вас есть, в основном делают одно и то же - аsed s///
. Вы используете оболочку для данных труб это сохраненное в памяти ,sed
так чтоsed
может заменить эти данные с другими данными , что оболочка , хранящиеся в его памяти , поэтомуsed
можно перенаправить его обратно к корпусу. Почему не просто[ "$var" = "$condition" ] && var=new_value
? Я также не получаю массивы - вы сохраняете имя массива, а[0]
затем используетеsed
для замены его значением в[1]
? Может быть, чат?filter
? Работает отлично как есть. Относительно того, как работает код по моей ссылке и почему я настроил его так, как я это сделал, да, давайте поговорим об этом в чате.Ответы:
Конечные символы новой строки удаляются перед сохранением значения в переменной. Вы можете сделать что-то вроде:
и использовать
${var%x}
вместо$var
. Например:Обратите внимание, что это решает проблему с завершающими символами новой строки, но не с нулевым байтом (если стандартный ввод не текстовый), так как согласно подстановке команды POSIX :
Но реализации оболочки могут сохранять нулевые байты.
источник
Вы можете использовать
read
встроенный для выполнения этого:Для сценария чтения STDIN это будет просто:
Я не уверен, что оболочки это будет работать, хотя. Но отлично работает как в bash, так и в zsh.
источник
-d
процесс подстановки (<(...)
) не являются переносимыми; этот код не будет работатьdash
, например.-d
, поэтому я положил отказ от ответственности в нижней части. ОП не определяет оболочку.dash
. Вы просто используете<<HEREDOC\n$(gen input)\nHEREDOC\n
- вdash
- который использует каналы для heredocs так же, как другие оболочки используют их для замены процесса - это не имеет значения. Всеread -d
дело в том, чтобы просто указать разделитель - вы можете сделать то же самое дюжиной способов - просто будьте в этом уверены. Хотя тебе понадобится хвостgen input
.IFS=''
вероятно, не нужно. Это означает, чтоread
не будет разрушаться пробелы. Но когда он читает в одну переменную, это не имеет никакого эффекта (что я могу вспомнить). Но я просто чувствую себя безопаснее, оставив его включенным :-)Вы можете сделать как:
Что бы вы ни делали, все равно
$var
исчезает, как только вы выходите из этой{ current shell ; }
группировки. Но это также может работать как:источник
$var
в{ ... }
группировке, не всегда возможно. Например, если эта команда выполняется внутри цикла, а нужно$var
вне цикла.{}
скобок .Это верно - и явно указано в ответе - что значение$var
является весьма вероятно , исчезнет полностью , когда{ current shell; }
группировка закрыто. Есть ли какой-то более явный способ сказать это, чем, что бы ты ни делал,$var
исчезает ...input | sed "s/'"'/&"&"&/g;s/.*/process2 '"'-> &'/" | sh
_variables
функцияbash_completion
, которая хранит результат подстановки команды в глобальной переменнойCOMPREPLY
. Если бы для сохранения новых строк использовалось конвейерное решение, результат был бы потерян. В вашем ответе создается впечатление, что оба решения одинаково хороши. Кроме того, следует отметить, что поведение конвейерного решения сильно зависит от оболочки: пользователь может протестироватьecho foo | { var=$(sed '$s/$/./'); var=${var%.}; } ; echo $var
с помощью ksh93 и zsh и считает, что все в порядке, хотя этот код содержит ошибки.$var
исчезает» (что на самом деле не соответствует действительности, поскольку это зависит от оболочки - поведение не определено POSIX), что является довольно нейтральным предложением. Второе решение лучше, потому что оно не страдает от этой проблемы, и его поведение одинаково во всех оболочках POSIX.