:
это другое имя для 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.
На самом деле, оказалось, что это не так сложно, просто уродливое выражение для написания. Для того, чтобы получить «остальную часть строки» вместо $5
awk, цикл по полям все еще теряет свой первоначальный пробел. Моя первая жизнеспособная идея заключается в том, чтобы использовать 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 содержит некоторые полезные сведения о сценариях, которые не сломаются, независимо от того, какие данные или имена файлов вы добавляете в сценарий.
:>
не один оператор. Это может быть легче понять, если вы прочитаете это как: > file
вместо этого.