Яка структура даних $ @ у оболонці?


13

Зазвичай ми використовуємо $@для представлення всіх аргументів, крім $ 0. Однак я не знаю, що таке структура даних $@.

Чому він поводиться інакше, $*коли, включаючи у подвійну цитату, хтось міг дати мені пояснення на рівні перекладача?

Його можна повторити для циклу, тому він, здається, є масивом. Однак це також може повністю перегукуватися з простим echo $@, якщо це масив, буде показаний лише перший елемент. Через обмеження оболонки я не можу написати більше експериментального коду для його виконання.

Різниця між цією публікацією : Цей пост показує, як $@поводиться інакше $*. Але мені цікаво про тип даних $@. Оболонка як мова інтерпретації, як і Python, повинна представляти дані відповідно до ряду основних типів. Або іншими словами, я хочу знати, як $ @ зберігається в пам'яті комп'ютера.

Це рядок, багаторядковий рядок чи масив?

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


1
Можливий дублікат Чому різниця між $ * і $ @?
Хаксіел

@Haxiel, я не думаю, що я написав їхню різницю внизу свого допису.
davmos

Вам краще послужити, перевіривши різницю у виході за допомогою printf '%s\n' "$@"та printf '%s\n' "$*". echoУтиліта просто виводить свої аргументи, незалежно від того , якщо вони є один або багато. Обидва - це масиви (рядків), але вони поводяться по-різному при подвійному цитуванні. Якщо будь-який був багаторядковий рядок, вони не змогли б зберігати багаторядкові рядки (що вони можуть). Незрозуміло, яке питання ви намагаєтеся вирішити.
Kusalananda

2
Ваше запитання є еквівалентом запитання, що таке @varзмінна в Perl, з точки зору її основного сховища. З точки зору звичайної програми Perl, це насправді не має значення, крім того, що вона доступна як масив / список (і той факт, що є контексти, в яких очікується список).
Kusalananda

Відповіді:


16

Це почалося як злом у оболонці Борна. У оболонці Борна було виконано розбиття слів IFS (після маркірування) на всі слова в контексті списку (аргументи командного рядка або слова, що forцикли циклічно включені ). Якщо у вас були:

IFS=i var=file2.txt
edit file.txt $var

Це друга лінія буде tokenised в 3 -х слів, $varбуде розширено, і розкол + Glob буде зроблено на всіх трьох слів, так що ви в кінцевому підсумку працює edз t, f, le.txt, f, в le2.txtякості аргументів.

Цитування частин цього завадить запобігти спліт + glob. Оболонка Борна спочатку запам'ятала, які символи були цитовані, встановивши 8-й біт на них внутрішньо (що змінилося пізніше, коли Unix став 8-бітовим чистим, але оболонка все-таки зробила щось подібне, щоб запам'ятати, який байт був цитований).

І те $*й $@інше було об'єднанням позиційних параметрів з проміжком між ними. Але була спеціальна обробка, $@коли всередині подвійних лапок. Якщо вони $1містяться foo barі $2містяться baz, "$@"вони розширяться до:

foo bar baz
^^^^^^^ ^^^

^s вище вказуючи, який із символів має 8-й біт). Там, де було вказано перший пробіл (було встановлено восьмий біт), але не другий (той додав проміжні слова).

І розділення аргументів здійснює розбиття IFS (якщо припустимо, що пробіл символу є $IFSтаким, яким він є за замовчуванням). Це схоже на те, як $*було розширено у попередника оболонки Маші (сама на основі оболонки Томсона, тоді як оболонка Борна була написана з нуля).

Це пояснює, чому в оболонці Bourne спочатку "$@"було б розширитись до порожнього рядка замість нічого взагалі нічого, коли список позиційних параметрів був порожнім (вам довелося обходити його ${1+"$@"}), чому він не зберігав порожні позиційні параметри і чому "$@"не не працювати, коли $IFSне містив символу пробілу.

Намір мав змогу передати аргумент дослівно до іншої команди, але це не спрацювало належним чином для порожнього списку, для порожніх елементів або коли $IFSне містило місця (перші два питання врешті-решт були виправлені в пізніших версіях ).

Оболонка Korn (на якій базується специфікація POSIX) змінила таку поведінку кількома способами:

  • Розбиття IFS проводиться лише в результаті розширень без котирування (не на буквальних словах, таких як editабо file.txtу наведеному вище прикладі)
  • $*і $@з'єднуються з першим символом $IFSабо пробілом, коли $IFSпорожній, за винятком котируваного "$@", цей столяр не котирується , як у оболонці Борна, а для котирується, "$*"коли IFSпорожній, позиційні параметри додаються без роздільника.
  • вона була додана підтримка масивів, і ${array[@]} ${array[*]}нагадує Борна $*і $@але починаючи з Indice 0 замість 1, і рідкісними (більше як асоціативні масиви) , що означає на $@насправді не можна розглядати як масив КШ (порівняйте з csh/ rc/ zsh/ fish/ , yashде $argv/ $*нормальні масиви).
  • Порожні елементи збереглися.
  • "$@"коли $#0 зараз розширюється до нічого замість порожнього рядка, "$@"працює, коли $IFSне містить пробілів, крім випадків, коли IFSпорожній. $*Без котировки без підстановок розширюється один аргумент (де позиційні параметри з'єднані з пробілом), коли $IFSпорожній.

ksh93 виправив решту кількох проблем вище. У ksh93, $*і $@розширюється до списку позиційних параметрів, відокремлюється незалежно від значення $IFS, а потім подальше розділення + globbed + brace-розширене у контекстах списку, $*об'єднане з першим байтом (не символом) $IFS, "$@"у списку контексти розширюється до списку позиційних параметрів, незалежно від значення $IFS. У контексті, що не є списком, як і в var=$@, $@з'єднується з простором незалежно від значення $IFS.

bashмасиви 's проектуються після ksh. Відмінності:

  • відсутність дужок-розгортань при розширенні без котирування
  • перший символ $IFSзамість байта
  • деякі кутові відмінності, такі як розширення, $*коли не котирується в контексті, що не є списком, коли $IFSвоно порожнє.

Хоча специфіка POSIX раніше була досить розпливчастою, вона тепер більш-менш визначає поведінку баш.

Це відрізняється від звичайних масивів у тому kshчи іншому bash:

  • Індекси починаються з 1 замість 0 (за винятком того, "${@:0}"що включає $0(не позиційний параметр, а у функціях дає назву функції чи не залежно від оболонки та того, як функція була визначена)).
  • Ви не можете призначати елементи окремо
  • це не рідко, ви не можете знімати елементи окремо
  • shift може бути використаний.

У zshабо yashтам, де масиви є нормальними масивами (не розрідженими, індекси починаються з одного, як у всіх інших оболонках, але ksh / bash), $*трактується як звичайний масив. zshмає $argvпсевдонім для нього (для сумісності з csh). $*- це те саме, що $argvабо ${argv[*]}(аргументи, об'єднані з першим символом, $IFSале все ще відокремлені в контекстах списку). "$@"подобається "${argv[@]}"або "${*[@]}"}проходить спеціальну обробку в стилі Корн.


8

Однак я не знаю, що таке структура даних $@.

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

Ми можемо розглядати позиційні параметри як частини $@, тому він має ряд чітких елементів ( $1, $2...), до яких можна отримати доступ самостійно і називатися послідовними натуральними числами. Це робить його чимось, що зазвичай називають масивом.

Синтаксис трохи дивний, хоча і навіть обмежений. Немає можливості змінювати окремий елемент масиву окремо. Натомість всю справу треба встановити відразу. (Ви можете використовувати, set -- "$@" fooщоб додати значення або set -- "${@:1:2}" foo "${@:3}"додати значення в середині. Але в обох випадках вам доведеться виписати весь отриманий список.)

Чому він поводиться інакше, $*якщо включати в подвійну цитату,

Тому що вони визначені, щоб поводитись інакше.

Однак це також може повністю перегукуватися з простим echo $@, якщо це масив, буде показаний лише перший елемент.

Якщо ви маєте на увазі факт, який a=(foo bar asdf); echo $aвиведе просто foo, то це здебільшого химерність синтаксису оболонки, а також факт, що масиви з назвою в стилі ksh створені пізніше, ніж позиційні параметри та $@. Рівнина $aє такою ж, як ${a[0]}і вона, має сумісне значення для одного скалярного значення, незалежно від того, чи aце масив чи проста скалярна змінна.

@Знак з посиланням на весь список був повторно з іменованими масивами в тому , що "${a[@]}"це спосіб отримати весь список. Порівняно з названими масивами, з $@, зайві дужки та дужки та ім’я просто пропускаються.

Або іншими словами, я хочу знати, як $@зберігається в пам'яті комп’ютера.

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

Це рядок, багаторядковий рядок чи масив?

Масив, в основному. Хоча вони відрізняються від масивів, названих у стилі ksh, оскільки вони можуть мати довільні неотримані цілі числа як індекси, а не просто послідовні, як з $@. (Тобто, іменований масив може бути розрідженим і мати, наприклад, індекси 1, 3і 4, з 0і 2відсутні. Це неможливо з позиційними параметрами.)

Це не один рядок, оскільки його можна розширити на окремі елементи, а виклик рядків елементів також не є правильним, оскільки будь-яка звичайна змінна або один із позиційних параметрів (елементів $@) також може містити нові рядки.

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

Ні. Але названі масиви, мабуть, корисніші в будь-якому випадку.


1
+1. TL: DR $@не є структурою даних, це одна з небагатьох функцій / операторів розширення структури даних про позиційні параметри.
Пітер Кордес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.