Як передати значення змінної stdin команди?


105

Я пишу сценарій оболонки, який повинен бути дещо захищеним, тобто не передає захищені дані через параметри команд і, бажано, не використовує тимчасові файли. Як я можу передати змінну stdin команди? Або, якщо це неможливо, як правильно використовувати тимчасові файли для такого завдання?


Чи може зловмисник змінитися $PATH? Так що catможна замінити/bin/cat "$@" | tee /attacker/can/read/this/file
12431234123412341234123

Відповіді:


74

Щось таке просто, як:

echo "$blah" | my_cmd

7
Остерігайтеся пробілів у змінній: echo "$blah"краще.
Джонатан Леффлер

13
Давайте подивимося, як ви поводитесь blah=-n, blah=-e... використовуйте printfзамість цього. unix.stackexchange.com/questions/65803/…
Каміло Мартін

1
це здається, що це було б крихким і схильним до помилок, ні?
ThorSummoner

19
Через 6 років, якби я міг видалити цю відповідь, я би (але не можу, тому що це було прийнято ...)
Олівер Чарльзворт

1
@OliverCharlesworth, чому б не відредагувати його для використання printf '%s\n' "$blah"? З цією зміною (уникаючи багатьох помилок в echo«s специфікації, який відмінний відповідь Стефан йде в докладно на Чому printfкраще echo? На Unix і Linux , або які розділ ЗАСТОСУВАННЯ з echoспецифікації дотиків лаконічніше) це прекрасно розумна відповідь.
Чарльз Даффі

192

Передати значення stdinв bash просто так:

your-command <<< "$your_variable"

Завжди переконайтесь, що ви ставите лапки навколо змінних виразів!

Будьте обережні, що це, ймовірно, буде працювати тільки в bashі не буде працювати sh.


39
Напевно <<<, гарантії не будуть доступні, вони не знаходяться в базі POSIX, наскільки я знаю. Вони працюватимуть, як очікувалося, до тих пір, поки ви лише працюєте ними bash. Я лише згадую це, тому що вони сказали, що "оболонка" не конкретно "баш". Хоча він і позначив це питання bash... так що це все одно є прийнятною відповіддю.
Дж. М. Бекер

Хоча це може бути і так, конфіденційна інформація, ймовірно, буде легше просочуватися, якщо використовувати echoметод завдяки створенню труби. Команда герестування буде оброблена повністю bash, хоча в цій ситуації (як зазначалося) ви краще знаєте, що вона буде працювати на ваш bash, інакше будь-яке повідомлення про помилку, отримане внаслідок непідтримки herestrings, також витікає зазначену інформацію.
Стівен Лу

@StevenLu Зачекайте, echoце вбудований. Жодної труби немає, правда? Це Unix, але це не може бути так багато Unix .
Каміло Мартін

4
@StevenLu printf '%s\n' "$var"дає ті самі результати, що echo "$var"і не порушується, якщо, наприклад var=-en, і навіть не вимагає баш.
Каміло Мартін

1
Зауважте також, що до рядка для сюди рядків додається новий рядок.
фунтові

19

Зауважте, що " echo "$var" | commandоперації означають, що стандартне введення обмежено рядками, що відлунюються". Якщо ви також хочете, щоб термінал був підключений, вам потрібно буде бути більш прихильним:

{ echo "$var"; cat - ; } | command

( echo "$var"; cat -   ) | command

Це означає, що перший рядок буде вмістом, $varа решта буде надходити з catчитання його стандартного вводу. Якщо команда не робить нічого надто фантазійного (спробуйте увімкнути редагування командного рядка або запустити так, як vimце робиться), то це буде добре. Інакше вам потрібно по-справжньому пофантазувати - я думаю, expectчи один із його похідних, ймовірно, буде доречним.

Позначення командного рядка практично ідентичні - але друге напівкрапка є необхідною для дужок, тоді як це не з дужками.


( echo "$LIST"; cat - ) | sed 1qце працює для мене, але мені потрібно натиснути ctrl d при запуску цього сценарію?
Герт Куйкенс

Так; cat -продовжує читати з клавіатури до EOF або переривань, так що ви повинні сказати йому EOF, набравши управління-D.
Джонатан Леффлер

чи є шлях навколо EOF? sed потреб cat
Герт Куйкенс

Вам зовсім не доведеться використовувати, catякщо ви не хочете вводити термінали, як у першому рядку. Або ви можете скористатися catсписком файлів. Або ... Якщо ви хочете, щоб команда читала вхід терміналу, ви повинні сказати, коли вона досягла кінця вводу. Або ви могли використовувати ( echo "$var"; sed /quit/q - ) | command; це триває, поки ви не введете рядок, що містить "quit". Ти можеш бути нескінченно винахідливим у тому, як справишся з цим. Остерігайтеся старої міської легенди програми, яка перестала працювати, коли користувачі почали працювати з Еквадором. Вони ввели назву столиці, Кіто та програму, що вийшла.
Джонатан Леффлер

Добре, якщо ти так кажеш. Але чому б не просто echo "$LIST" | sed 1q | ...? Все залежить від того, про що ти йдеш. <<EOFПозначення повинні вимагати EOF на початку лінії на своїй власній де - то файл. Я б не користувався цим, я думаю - але я все ще не впевнений, чого ти намагаєшся досягти. На практиці просто, echo "$LIST" | commandабо echo $LIST | command, ймовірно, достатньо (і важливо, щоб ви знали значення різниці між ними).
Джонатан Леффлер

16

Мені сподобалась відповідь Мартіна, але у неї є деякі проблеми залежно від того, що є в змінній. Це

your-command <<< """$your_variable"""

краще, якщо змінна містить "або!


4
Але чому? Крім того, я не можу відтворити жодних проблем: foo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"добре працює для мене. Що саме роблять троє "? AFAIK ви просто готуєте та додаєте порожню рядок.
phk

Спробуйте щось справжнє. Як і ваша команда - ssh somehost. і ваша змінна - це сценарій оболонки.
Роберт Джейкобс

16
(cat <<END
$passwd
END
) | command

Це catнасправді не потрібно, але воно допомагає краще структурувати код і дозволяє використовувати більше команд у дужках як вхід до вашої команди.


Але цей метод дозволяє передавати декілька рядків до вашої команди, а також дозволяє пробіли в$passwd
PoltoS

4
Це найкраща відповідь на даний момент, що не просочується змінного вмісту в трубу або процес прослуховування.
користувач2688272

8

Відповідно до відповіді Мартіна, є функція bash під назвою Here Strings (що сама є варіантом більш широко підтримуваної функції Here Documents ).

http://www.gnu.org/software/bash/manual/bashref.html#Here-Strings

3.6.7 Тут рядки

Варіант тут документів, формат:

<<< word

Слово розгортається і подається команді на його стандартному вході.

Зауважте, що тут рядки здаються лише базовими, тому для покращення переносимості вам, мабуть, краще з оригінальною функцією Here Documents, відповідно до відповіді PoltoS:

( cat <<EOF
$variable
EOF
) | cmd

Або більш простий варіант вищезазначеного:

(cmd <<EOF
$variable
EOF
)

Ви можете опустити (і ), якщо не хочете, щоб це перенаправлено далі в інші команди.


5

Цей надійний і портативний спосіб уже з'явився в коментарях. Це має бути окрема відповідь.

printf '%s' "$var" | my_cmd

або

printf '%s\n' "$var" | my_cmd

Примітки:

  • Це краще, ніж echo, причини тут: Чому printfкраще, ніж echo?
  • printf "$var"неправильно. Перший аргумент формату , де різні послідовності подобається %sабо \nякі інтерпретуються . Для передачі змінної права вона не повинна інтерпретуватися як формат.
  • Зазвичай змінні не містять останніх рядків. Колишня команда (з %s) передає змінну як є. Однак інструменти, що працюють з текстом, можуть ігнорувати або скаржитися на неповний рядок (див. Чому текстові файли закінчуються новим рядком? ). Тож вам може знадобитися остання команда (з %s\n), яка додає символ нового рядка до вмісту змінної. Неочевидні факти:

    • Тут рядок у Bash ( <<<"$var" my_cmd) додає новий рядок.
    • Будь-який метод, який додає новий рядок, призводить до не порожнього stdin my_cmd, навіть якщо змінна порожня або невизначена.

4

Спробуйте це:

echo "$variable" | command

але чи не відображатиметься змінна $ змінна, наприклад, у висновку, ps -uколи ехо працює?

2
ні, це не буде. echoце вбудований, тому немає жодного процесу для показу в ps
unbeli

2
Остерігайтеся пробілів у змінній: echo "$variable"краще.
Джонатан Леффлер

правильно, Баш з'їсть подвійні простори, розумніших снарядів не буде
unbeli

-1

Просто зробіть:

printf "$my_var" | my_cmd

Якщо var не містить пробілів, то лапки можуть бути пропущені.
Якщо ви використовуєте bash, ви також можете:

echo -n "$my_var" | my_cmd

Уникайте використання ехо-сигналу без -n, оскільки воно передасть повний шлях із додаванням рядкової лінії в кінці.


1
не працює, якщо є $ my_var %s, printf нічого не надрукує. my_var="%s"; printf "$my_var"; - може, спробувати printf "%s" "$my_var" | my_cmd ?
hanshenrik
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.