Використання "під час читання ..." у скрипті linux


34

Невже хтось може пояснити, як працює наступний код?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

В Зокрема, я хотів би знати , чому вихід з цієї петлі 3 4 5 6 2 1, а 3 2 1й 6 5 4на два окремих рядках? Я не можу, здається, обернути свою думку ...

Відповіді:


41

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

У вашому випадку $aпризначається 1, $bпризначається 2і $cрешта 3 4 5 6.


Дякую Флоріану! Тепер це має сенс ... Я чомусь думав, що пробіли будуть обмежувати кожне змінне читання, але, мабуть, ні. Я вдячний за твою допомогу!!
linuxgringo

24

Переписування циклу таким чином виявляє, що відбувається:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

Це дає як результат:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

Спершу зауважте, що виконується лише одна команда echo. Якби це було запущено не один раз, ви, серед іншого, побачили б (iteration beginning)і (iteration ending)підрядки надруковані не один раз.

Це означає, що наявність whileциклу тут насправді нічого не досягає. readВбудований читає розділених пробілами текст 1 в кожній заданій змінній. Додатковий вхід додається до кінця останньої вказаної змінної. 2 Таким чином , змінні aі bприймають значення 1і , 2відповідно, в той час як cприймає значення 3 4 5 6.

Коли умова циклу ( while read a b c) оцінюється вдруге, більше немає вхідних даних з труби (ми лише переносимо в неї один рядок тексту), тому readкоманда визначає значення false, а не true, і цикл зупиняється (перш ніж виконувати тіло вдруге).

1 : Щоб бути технічна, вбудованої , при передачі власних назв змінних в якості аргументів, зчитує інформацію, розділивши його на окремі «слова» , коли він зустрічає IFS пробільні (дивись також це питання і в цій статті ).read

2 : readповедінка заклинювання будь-яких додаткових полів введення в останню вказану змінну є спочатку неінтуїтивною для багатьох скрипторів. Це стає легше зрозуміти, коли ти вважаєш, що, як йдеться у відповіді Флоріана Діеша , readзавжди (намагаюся) прочитати цілий рядок - і readце призначено для використання як із циклом, так і без нього.


Елія, дякую, що знайшов час для пояснення всіх подробиць. У whileцьому прикладі я підозрював, що не слугував нормальній меті, але потім readкоманда мене відкинула ... Я якось інтерпретував це як "поки read a b cне помилково, роби echo ...". Дякую, що пояснили, як це насправді працювало. Я вчора зіткнувся з цим кодом і знав, що він буде
помилятись,

@linuxgringo На насправді, тіло циклу буде виконуватися кожного разу , read a b cістинно, і умова циклу ( read a b c) не запускати більш ніж один раз. Біт він оцінює справжній лише 1-й раз. Другий раз, більше немає інформації, яку слід читати з труби, тому зустрічається кінець файлу , що призводить readдо повернення помилкового . (Докладні відомості див. В останньому розділі виводу help read"Стан виходу" для деталей, зазначивши, що в сценарії оболонки нуль означає істинне, а ненульовий означає помилкове значення.) Якщо введено більше одного рядка вводу while read ..., тіло циклу буде виконувати кілька разів.
Елія Каган
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.