Деякі люди мають таке помилкове поняття, що read
це команда читати рядок. Це не.
read
читає слова з (можливо, продовження зворотної косої риски), де слова $IFS
розмежовані і зворотна косою рисою може бути використана для виходу з роздільників (або продовження рядків).
Родовим синтаксисом є:
read word1 word2... remaining_words
read
читає STDIN один байт в той час , поки він не знайде неекранований символ нового рядка (або кінець вхідного тексту), розщеплюється , що в відповідності зі складними правилами і зберігає результат цього поділу на $word1
, $word2
... $remaining_words
.
Наприклад, на вході, як-от:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
і зі значенням за замовчуванням $IFS
, read a b c
призначить:
$a
⇐ foo
$b
⇐ bar baz
$c
⇐ blah blahwhatever whatever
Тепер, якщо було передано лише один аргумент, цього не стане read line
. Це все ще read remaining_words
. Обробка зворотного косого ряду все ще виконується, символи пробілів IFS все ще видаляються з початку і в кінці.
-r
Опція видаляє обробку зворотної косою. Тож та сама команда, що була наведена вище -r
, замість цього призначить
$a
⇐ foo
$b
⇐ bar\
$c
⇐ baz bl\ah blah\
Тепер для розділення частини важливо усвідомити, що існує два класи символів $IFS
: символи пробілу IFS (а саме пробіл та вкладка (і новий рядок, хоча тут це не має значення, якщо ви не використовуєте -d), що також трапляється бути у стандартному значенні $IFS
) та інші. Лікування цих двох класів персонажів різне.
З IFS=:
( :
будучи не IFS символ пробілу), вхід як :foo::bar::
би розщеплюється на ""
, "foo"
, ""
, bar
і ""
(і додатково ""
з деякими реалізаціями , хоча це не має значення , за винятком read -a
). Хоча якщо ми замінимо це :
на простір, розщеплення робиться лише на foo
і bar
. Тобто провідні та відсталі ігноруються, і послідовності з них трактуються як одна. Існують додаткові правила, коли символи пробілів та пробілів не поєднуються $IFS
. Деякі реалізації можуть додавати / видаляти спеціальну обробку, подвоюючи символи в IFS ( IFS=::
або IFS=' '
).
Тож тут, якщо ми не хочемо, щоб провідні та відмінні символи пробілу були зняті, нам потрібно видалити ці символи пробілу IFS з IFS.
Навіть із символами IFS-непробільного простору, якщо рядок введення містить один (і лише один) цих символів, і це останній символ у рядку (як IFS=: read -r word
на вході, як foo:
) із оболонками POSIX (не, zsh
ані деякі pdksh
версії), цей вхід вважається одним foo
словом, оскільки в цих оболонках символи $IFS
розглядаються як термінатори , тому word
міститимуть foo
, не foo:
.
Отже, канонічним способом зчитування одного рядка введення з read
вбудованим є:
IFS= read -r line
(зауважте, що для більшості read
реалізацій це працює лише для текстових рядків, оскільки символ NUL не підтримується, за винятком zsh
).
Використовуючи var=value cmd
синтаксис, переконайтеся, що IFS
він встановлюється по-різному лише протягом тривалості цієї cmd
команди.
Примітка історії
read
Вбудований був введений Bourne оболонки і вже читати слова , а НЕ лінії. У сучасних оболонок POSIX є кілька важливих відмінностей.
Оболонка Bourne read
не підтримувала -r
параметр (який був введений оболонкою Korn), тому немає жодного способу відключити обробку зворотної косої риси, окрім попередньої обробки вводу чимось подібним sed 's/\\/&&/g'
.
Оболонка Борна не мала такого поняття про два класи персонажів (що знову було введено ksh). В оболонці Борна все символи пройти таке ж лікування , як IFS пробільні символи роблять в KSH, тобто IFS=: read a b c
на вході , як foo::bar
би призначити bar
на $b
, а не пустити рядок.
У оболонці Борна:
var=value cmd
Якщо cmd
це вбудований (як read
є), var
залишається встановленим value
після cmd
закінчення. Це особливо важливо, $IFS
тому що в оболонці Борна $IFS
використовується для розділення всього, а не тільки розширень. Крім того, якщо ви видалите пробіл із символу $IFS
оболонки Борна, він "$@"
більше не працює.
У оболонці Bourne перенаправлення складеної команди змушує її запускатись в нижній частині корпусу (у ранніх версіях навіть такі речі, як, read var < file
або exec 3< file; read var <&3
не працювали), тому в оболонці Bourne рідко можна було використовувати read
будь-що, крім введення користувача в термінал (де сенс обробки продовження рядка мав сенс)
Деякі Unices (наприклад, HP / UX, також є один в util-linux
) все ще мають line
команду зчитувати один рядок входу (який раніше був стандартною командою UNIX до єдиної специфікації UNIX версії 2 ).
Це в основному те саме, що head -n 1
за винятком того, що він читає один байт за один раз, щоб переконатися, що він не читає більше одного рядка. У цих системах ви можете:
line=`line`
Звичайно, це означає нерестування нового процесу, виконайте команду і прочитайте її вихід через трубу, так що набагато менш ефективний, ніж ksh IFS= read -r line
, але все ж набагато більш інтуїтивно зрозумілий.