Что означает этот странный символ «:>» в bash

47

Я нашел что-то в сценарии, но не принадлежал к основному сценарию. Был :>в очереди.

Не могли бы вы объяснить мне, что это значит?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile
diego9403
источник
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и echoвыводит их file. Он также делает переменные из того, что читает ... Если вы хотите получить определенный ответ, пожалуйста, задайте свой вопрос.
Дэвид Постилл
2
@ diego9403: readполучает информацию от стандартного ввода. Само по себе, он будет читать то, что вы печатаете. Поскольку stdin был перенаправлен <otherfileна, содержимое otherfile"вводится" в stdin. Таким образом, readзначения получаются построчно в переменные $ A, $ B, $ C, $ D и $ E.
Slebetman
Так что это просто более неясная альтернатива truncateиз coreutils?
Федерико Полони
1
@PeterCordes Я не имел в виду «неясный», как в «это необычно», но как «это менее понятно для читателя».
Федерико Полони
29

Это похоже на причудливый способ создания нового файла. In bash :является пустой командой:

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

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>перенаправляет вывод :в файл.

Аркадиуш Драбчик
источник
2
Он также будет
обрезать
2
да, это то, что >делает
Аркадиуш Драбчик
2
:это сокращение для true. Возможно в некоторых оболочках, trueразве не встроенный? Оба встроены в Bash.
Питер Кордес
12

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

Соединение этих двух частей :> file- довольно распространенная идиома для усечения файлов. : >fileТем не менее, большинство людей пытались бы сделать это менее странным, когда писали .


Поскольку вы спросили в комментарии о 2-й строке, я превращу свои комментарии в ответ. (даже если вы не задавали это в своем вопросе.)

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.

Установка разделителя поля вывода на ;означает, что вы можете просто передать несколько полей в качестве аргументов для печати. Оболочка readприсваивает последнюю переменную всей оставшейся части строки с пробелами, но нет способа сказать, чтобы awk делился только на 5. Если это важно, возможно, просто продолжайте использовать цикл bash, потому что это неудобно в awk. Perl делает это легко, поскольку он splitможет принимать аргументы max-fields, но запускать его намного медленнее, чем 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 означает заключить в кавычки следующее нажатие клавиши как буквальный символ, так как редактирование строки в стиле bash в emacs такое же, как и в действительности emacs.

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

Питер Кордес
источник