Що означає цей дивний символ ":>" в баші


47

Я знайшов щось у сценарії, але не належав до основного сценарію. Був :>у черзі.

Чи можете ви пояснити мені, що це означає?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile

6
Важливо, що :>це не один оператор. Це може бути легше зрозуміти, якщо ви читаєте це як : > fileнатомість.
jpfx1342

Це означає , що людина , що пише сценарій повинен був перенаправлений висновок петлі в файл: while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. Або ще краще, вони повинні були використовувати правильний інструмент для роботи, awk, як запропонував Петро . В сторону ви майже завжди хочете використовувати -rперемикач ізread .
Том Фенех

Зовні баш, це було б посмішкою для ворони.
smci

Відповіді:


46

Був:> у рядку скрипта bash. Що це означає?

:> file

Це короткий спосіб сказати:

  • Якщо fileйого не існує, створіть його іншим чином, усічіть його до 0байтів.

Це означає, що ви можете бути впевнені, що fileіснує, і він порожній.

Ви також можете використовувати, > fileале :> fileбільш портативний.

Див. Запитання щодо переповнення стека. Яка мета ':' (двокрапки) GNU Bash Builtin? для отримання додаткової інформації.


Я не розумію другого рядка. Я думав, що читає прочитані змінні. Командний відгомін теж дивний. Чи можете ви пояснити?
diego9403

Я не експерт в Unix , але я думаю , що друга лінія читає речі з otherfileі echoS їх до file. Він також робить змінні з того, що він читає ... Якщо ви хочете однозначно відповісти, будь ласка, задайте власне запитання.
DavidPostill

2
@ diego9403: readотримує вхід від stdin. Сам по собі він прочитав би те, що ти вводиш. Оскільки stdin були перенаправлені до, <otherfileто вміст otherfile"вводиться" в stdin. Таким чином, readотримує значення по черзі у змінні $ A, $ B, $ C, $ D і $ E.
slebetman

Тож це просто більш незрозуміла альтернатива truncateвід Coreutils?
Федеріко Полоні

1
@PeterCordes Я не мав на увазі "незрозумілий", як у "це нечасто", але як у "менш зрозумілому для читача".
Федеріко Полоні

29

Це виглядає як химерний спосіб створення нового файлу. У bash :- це нульова команда:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>перенаправляє вихід :до файлу.


2
Він також
вріже

2
так, саме це >робить
Аркадіуш Драбчик

2
:це стенограма для true. Можливо, в деяких оболонках, trueчи не вбудований? Обидва вбудовані в баш.
Пітер Кордес

12

:інша назва для true. Обидва є вбудованими оболонками в баш, але немає /bin/:, тільки a /bin/true. Перенаправлення виводу викликає оболонку open(2)у файл із O_CREAT|O_TRUNC. Якщо нічого не записано, воно залишається на нульовій довжині.

Складання цих двох творів разом :> fileє досить поширеною фразою для обрізання файлів. : >fileОднак, більшість людей намагаються зробити його менш дивним на письмі .


Оскільки ви запитали в коментарі про другий рядок, я перетворять свої коментарі у відповідь. (навіть якщо ви не ставили цього питання у своєму запитанні.)

2-й рядок - це цикл, який читає рядки з otherfileдеяких названих змінних. Корпус циклу використовує echoдля друку їх ;роздільниками замість того, який пробіл у них був раніше. fileзакривається та повторно відкривається (для додавання) кожну ітерацію, оскільки переспрямування знаходиться всередині циклу. Використання while ...;do read -r ...;done <otherfile >fileб менше смокче, і уникнути необхідності спочатку скорочувати файл. read -rне їсть \як персонаж втечі.

Обробка тексту в bash відбувається досить повільно. Частина цього неминуча: readмає проходити один байт за один раз (один read(2)системний виклик на байт), щоб уникнути зайвого видалення кінця рядка. Краще використовувати правильний інструмент для роботи:

awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile  >file

--означає, що ваш сценарій не зламається, якщо otherfileвін названий чимось нерозумним --version.

Встановлення розділювача вивідного поля ;означає, що ви можете просто передавати кілька полів у вигляді аргументів для друку. Shell readприсвоює всю останню лінію з пробілом до останньої змінної, але немає способу сказати awk лише розділитись на 5. Якщо це важливо, можливо, просто продовжуйте використовувати цикл bash, тому що це незручно в awk. Perl робить це легко, оскільки його splitможна взяти аргумент max-полів, але запускати його набагато повільніше, ніж awk.

Насправді, виявилося, це не так складно, просто потворне зворотнє висловлювання для написання. Щоб отримати спокій від лінії замість $5awk, перекидання полів все ще втрачає початковий пробіл. Моя перша життєздатна ідея - використовувати gensubв $0(цілому рядку) для видалення перших 4 полів (тобто непробіл, за яким пробіл), залишаючи все інше:

awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file

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

Зверніть увагу, як це так само, printяк і раніше, але tailзамість цього $5.

echo 'A  B c DD    e      f g    f' | 
  awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
   print $1, $2, $4, tail, $3 }'

A;B;DD;e       f g    f;c

Це було б більш вражаюче, якби я міг скопіювати / вставити літерал і показати, що він потрапив у висновок. Введіть один у bash з ^ Q. ctrl-Q означає Цитувати наступне натискання клавіші як буквальний символ, оскільки редагування рядків у стилі emacs є таким самим, як і фактичні для цього.

http://mywiki.wooledge.org/BashFAQ має кілька корисних матеріалів щодо створення сценаріїв способами, які не порушуються незалежно від того, які дані та назви файлів ви викидаєте за сценарієм.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.