Это так называемые операторы оболочки, и да, их больше. Я дам краткий обзор наиболее распространенных среди двух основных классов, управляющих операторов и операторов перенаправления , а также того, как они работают в отношении оболочки bash.
;
: Выполняет одну команду за другой, независимо от результата первой.
command1 ; command2
Сначала command1
запускается, на переднем плане, и как только он закончится, command2
будет запущен.
Новая строка, которая отсутствует в строковом литерале или после определенных ключевых слов, не эквивалентна точке с запятой. Список ;
простых команд с разделителями по-прежнему является списком - так как в синтаксическом анализаторе оболочки все равно необходимо продолжить чтение простых команд, которые следуют за ;
простой командой с разделителями перед выполнением, тогда как символ новой строки может разделять весь список команд - или список списков. Разница невелика, но сложна: поскольку оболочка не имеет предыдущего императива для чтения данных после новой строки, новая строка отмечает точку, в которой оболочка может начинать вычислять простые команды, которые она уже прочитала, тогда как точка с запятой ;
делает не.
&
: Это запустит команду в фоновом режиме, что позволит вам продолжить работу в той же оболочке.
command1 & command2
Здесь command1
он запускается в фоновом режиме и сразу же command2
начинает работать на переднем плане, не дожидаясь command1
выхода.
Новая строка после command1
необязательна.
&&
: Используется для создания списков AND, позволяет выполнять одну команду, только если другая успешно завершена.
command1 && command2
Здесь command2
будет выполняться после command1
завершения и только в случае command1
успеха (если его код выхода был 0). Обе команды выполняются на переднем плане.
Эта команда также может быть написана
if command1
then command2
else false
fi
или просто, if command1; then command2; fi
если статус возврата игнорируется.
||
: Используется для создания списков ИЛИ, позволяет выполнять одну команду, только если другая не удалась.
command1 || command2
Здесь command2
будет работать только в случае command1
неудачи (если он вернул состояние выхода, отличное от 0). Обе команды выполняются на переднем плане.
Эта команда также может быть написана
if command1
then true
else command2
fi
или короче if ! command1; then command2; fi
.
Обратите внимание, что &&
и ||
левоассоциативны; см. Приоритет логических операторов оболочки &&, || для дополнительной информации.
!
: Это зарезервированное слово, которое действует как оператор «не» (но должен иметь разделитель), используется для отмены возвращаемого состояния команды - возвращает 0, если команда возвращает ненулевой статус, возвращает 1, если возвращает состояние 0 Также логическое НЕ для test
утилиты.
! command1
[ ! a = a ]
И истинный оператор НЕ внутри арифметических выражений:
$ echo $((!0)) $((!23))
1 0
Они позволяют вам контролировать ввод и вывод ваших команд. Они могут появляться в любом месте в пределах простой команды или могут следовать за командой. Перенаправления обрабатываются в порядке их появления слева направо.
<
: Дает ввод в команду.
command < file.txt
Выше будет выполнено command
на содержание file.txt
.
<>
: то же, что и выше, но файл открыт в режиме чтения + записи, а не только для чтения :
command <> file.txt
Если файл не существует, он будет создан.
Этот оператор используется редко, потому что команды обычно читают только из их стандартного ввода, хотя это может пригодиться в ряде конкретных ситуаций .
>
: Направляет вывод команды в файл.
command > out.txt
Выше сохранит вывод command
как out.txt
. Если файл существует, его содержимое будет перезаписано, а если он не существует, он будет создан.
Этот оператор также часто используется, чтобы выбрать, следует ли печатать что-либо со стандартной ошибкой или стандартным выводом :
command >out.txt 2>error.txt
В приведенном выше примере >
перенаправляет стандартный вывод и 2>
перенаправляет стандартную ошибку. Вывод также может быть перенаправлен с использованием, 1>
но, поскольку это значение по умолчанию, 1
обычно опускается и записывается просто как >
.
Таким образом, чтобы работать command
на file.txt
и сохранить свой выход в out.txt
и сообщения об ошибках в error.txt
Убежишь:
command < file.txt > out.txt 2> error.txt
>|
: Делает то же, что и >
, но будет перезаписывать цель, даже если оболочка была настроена на отказ от перезаписи (с помощью set -C
или set -o noclobber
).
command >| out.txt
Если out.txt
существует, вывод command
заменит его содержимое. Если он не существует, он будет создан.
>>
: Делает то же самое >
, за исключением того, что, если целевой файл существует, новые данные добавляются.
command >> out.txt
Если out.txt
существует, вывод command
будет добавлен к нему, после того, что уже есть в нем. Если он не существует, он будет создан.
&>
, >&
, >>&
И &>>
: (нестандартные). Перенаправить как стандартную ошибку, так и стандартный вывод, заменяя или добавляя соответственно.
command &> out.txt
command
Будут сохранены как стандартная ошибка, так и стандартный вывод out.txt
, перезаписывая его содержимое или создавая его, если он не существует.
command &>> out.txt
Как и выше, за исключением того, что, если out.txt
существует, вывод и ошибка command
будут добавлены к нему.
&>
Вариант происходит в bash
то время как >&
вариант происходит от CSH (десятилетиями ранее). Они оба конфликтуют с другими операторами оболочки POSIX и не должны использоваться в переносимых sh
скриптах.
<<
А вот документ. Он часто используется для печати многострочных строк.
command << WORD
Text
WORD
Здесь command
будет принимать все, пока не найдет следующее вхождение WORD
, Text
в приведенном выше примере, в качестве ввода. Хотя WORD
это часто EoF
или их вариации, это может быть любая буквенно-цифровая (и не только) строка, которая вам нравится. Когда WORD
заключено в кавычки, текст в этом документе обрабатывается буквально, и никаких расширений не выполняется (например, для переменных). Если оно не заключено в кавычки, переменные будут расширены. Для более подробной информации смотрите руководство по bash .
Если вы хотите направить вывод command << WORD ... WORD
непосредственно в другую команду или команды, вы должны поместить конвейер в ту же строку, что << WORD
и вы не можете поместить его после завершающего слова или в следующей строке. Например:
command << WORD | command2 | command3...
Text
WORD
<<<
Здесь строки, похожие на документы, но предназначенные для одной строки. Они существуют только в Unix-порте или rc (где он возник), zsh, в некоторых реализациях ksh, yash и bash.
command <<< WORD
Все, что задано как WORD
, раскрывается, и его значение передается в качестве входных данных command
. Это часто используется для передачи содержимого переменных в качестве ввода в команду. Например:
$ foo="bar"
$ sed 's/a/A/' <<< "$foo"
bAr
# as a short-cut for the standard:
$ printf '%s\n' "$foo" | sed 's/a/A/'
bAr
# or
sed 's/a/A/' << EOF
$foo
EOF
Это касается только наиболее распространенных операторов оболочек типа Борна. У некоторых оболочек есть несколько дополнительных операторов перенаправления.
bash
. Это готовится как канонический Q & A, чтобы закрыть различные вопросы "Что делает эта странная штука", и большинство из них от пользователей bash. Я надеюсь, что кто-то другой подойдет и ответит за не-bash-оболочки, но выделение bash-специфических имеет большой смысл. Я должен проверить, хотя, я не знаю, какие они находятся на моей голове.&>
,>>>
и<<<
все не являются posix, так как это ссылка на не только не алфавитные символы в имени здесь-документа. В этом ответе также очень мало говорится о том, как они работают - например, почти бесполезно говорить о простой команде и команде, не объясняя, что это такое и как решает оболочка.false
), а код выхода 0 указывает на успех (нетtrue
). Это всегда было так и вполне стандартно. Код выхода, отличный от 0, указывает на ошибку во всех известных мне средах.Предупреждение относительно «>»
Новички Unix, которые только что узнали о перенаправлении ввода / вывода (
<
и>
), часто пробуют такие вещи, какили же
или, почти эквивалентно,
(
grep
,sed
,cut
,sort
, Иspell
примеры команд , которые люди склонны использовать в конструкциях , как эти.) Пользователи удивлены, обнаружив , что эти сценарии приводят к файлу становятся пустым.Нюанс, который, кажется, не упоминается в другом ответе, можно найти в первом предложении раздела перенаправления bash (1) :
Первые пять слов должны быть выделены жирным шрифтом, курсивом, подчеркнуты, увеличены, мигать, окрашены в красный цвет и отмечены значком, чтобы подчеркнуть тот факт, что оболочка выполняет запрошенное перенаправление (я) перед выполнением команды . И помни также
Итак, в этом примере:
оболочка открывает
roster
файл для записи, обрезая его (т. е. отбрасывая все его содержимое), доsort
запуска программы. Естественно, ничего не поделаешь для восстановления данных.Можно наивно ожидать, что
может быть лучше. Поскольку оболочка обрабатывает перенаправления слева направо, она открывается
poem
для чтения (дляtr
стандартного ввода в России), прежде чем открывает ее для записи (для стандартного вывода). Но это не помогает. Несмотря на то, что эта последовательность операций дает два дескриптора файла, они оба указывают на один и тот же файл. Когда оболочка открывает файл для чтения, содержимое все еще там, но оно все еще остается забитым до выполнения программы.Итак, что с этим делать?
Решения включают в себя:
Проверьте, имеет ли ваша программа внутреннюю возможность указать, куда выводится результат. На это часто указывает токен
-o
(или--output=
). В частности,примерно эквивалентно
за исключением того, что в первом случае
sort
программа открывает выходной файл. И это не достаточно , чтобы открыть выходной файл умного , пока после того, как она прочитала все входной файл (ов).Точно так же, по крайней мере, в некоторых версиях
sed
есть опция-i
(edit in n place), которую можно использовать для записи вывода обратно во входной файл (опять же, после того , как все входные данные были прочитаны). Редакторы какed
/ex
,emacs
,pico
иvi
/vim
разрешить пользователю редактировать текстовый файл и сохранить отредактированный текст в исходном файле. Обратите внимание, чтоed
(по крайней мере) можно использовать не в интерактивном режиме.vi
имеет связанную особенность. Если вы напечатаете , он запишет содержимое буфера редактирования в , прочитает вывод и вставит его в буфер (заменяя исходное содержимое).:%!command
Entercommand
Простой, но эффективный:
Это имеет недостаток, заключающийся в том, что, если
input_file
это ссылка, она (вероятно) будет заменена отдельным файлом. Кроме того, новый файл будет принадлежать вам с защитой по умолчанию. В частности, это несет в себе риск того, что файл в конечном итоге станет доступным для чтения, даже если оригиналinput_file
не был.Варианты:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
который все еще (потенциально) оставит
temp_file
читабельный мир. Даже лучше:cp input_file temp_file && command … temp_file > input_file && rm temp_file
Они сохраняют статус ссылки, владельца и режим (защиту) файла, потенциально за счет вдвое большего количества операций ввода-вывода. (Возможно, вам придется использовать опцию вроде
-a
или-p
on,cp
чтобы сказать ей, чтобы сохранить атрибуты.)command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(разбито на отдельные строки только для удобства чтения) Это сохраняет режим файла (и, если вы root, владелец), но делает его принадлежащим вам (если вы не root) и делает его новым, отдельный файл.
Этот блог (редактирование файлов на месте) предлагает и объясняет
Это требует, чтобы
command
была возможность обрабатывать стандартный ввод (но почти все фильтры могут). Сам блог называет это рискованным препятствием и препятствует его использованию. И это также создаст новый отдельный файл (не связанный ни с чем), принадлежащий вам и с разрешениями по умолчанию.Пакет moreutils имеет команду под названием
sponge
:Смотрите этот ответ для получения дополнительной информации.
Вот что удивило меня: syntaxerror говорит :
Следующее может работать в этом случае:
sort
илиtr
без-d
или-s
опции), вы можете попробовать См. Этот ответ и этот ответ для получения дополнительной информации, включая объяснение вышеизложенного, и альтернативы, которые работают, если ваша команда гарантирует получение того же количества выходных данных, что и вводимых данных, или меньше (напримерgrep
, илиcut
). Преимущество этих ответов заключается в том, что они не требуют свободного места (или требуют совсем немного). Ответы, приведенные выше в форме, явно требуют наличия достаточного свободного места, чтобы система могла одновременно хранить весь входной (старый) файл и выходной (новый) файл; это не очевидно верно и для большинства других решений (например, и ). Исключение: вероятно, потребуется много свободного места, потому чтоcommand … input_file > temp_file && …
sed -i
sponge
sort … | dd …
sort
ему нужно прочитать все входные данные, прежде чем он сможет записать какой-либо вывод, и он, вероятно, буферизует большую часть, если не все эти данные, во временном файле.dd
ответу выше. Синтаксис открывает файл с именем файла с дескриптором для ввода и вывода , без усечения его - своего рода комбинации и . Примечание. Некоторые программы (например, и ) могут отказать в запуске в этом сценарии, поскольку они могут обнаружить, что вход и выход - это один и тот же файл. См. Этот ответ для обсуждения вышеизложенного и сценария, который заставляет этот ответ работать, если ваша команда гарантированно выдаст то же количество выходных данных, что и вводимые данные, или меньше . Предупреждение: я не проверял сценарий Питера, поэтому я не ручаюсь за него.n<> file
n
n<
n>
cat
grep
Итак, в чем был вопрос?
Это была популярная тема на U & L; он адресован в следующих вопросах:
iconv
замену входного файла с преобразованным выводом?shuf file > file
оставляет пустой файл?sort
команда дает мне пустой файл?tr
stdout в файл… И это не считая Super User или Ask Ubuntu. Я включил много информации из ответов на вышеупомянутые вопросы здесь в этом ответе, но не все. (То есть, для получения дополнительной информации, прочитайте перечисленные выше вопросы и ответы на них.)
PS У меня нет связи с блогом, который я цитировал выше.
источник
/tmp
.dash
это будет оболочка восстановления по умолчанию в Ubuntu, и она не только не понимает<<<
Herestring, но также получает анонимные каналы для<<
heredocuments и не связывается с${TMPDIR:-/tmp}
этим. цель вообще. Смотрите это или это для демонстраций по обработке документов здесь. Кроме того, почему столько же выхода или меньше предупреждений?dd … conv=notrunc
и1<>
ответы никогда не усекают выходной файл, поэтому, если выходные данные команды меньше входных (например,grep
), в конце файла останутся некоторые байты оригинала. И, если на выходе больше , чем на входе (например,cat -n
,nl
или (потенциально)grep -n
), есть риск перезаписи старых данных , прежде чем вы читали его.Дополнительные замечания по
;
,&
,(
и)
Обратите внимание, что некоторые команды в ответе Тердона могут быть нулевыми. Например, вы можете сказать
(без
command2
) Это эквивалентно(т. е. он просто работает
command1
на переднем плане и ждет его завершения.(без no
command2
) запуститсяcommand1
в фоновом режиме и сразу же выдаст другое приглашение оболочки.В отличие от этого
command1 &&
,command1 ||
иcommand1 |
не имеет никакого смысла. Если вы введете один из них, оболочка (вероятно) предположит, что команда продолжается в другой строке. Он отобразит подсказку вторичной (продолжающейся) оболочки, которая обычно установлена>
, и продолжит чтение. В сценарии оболочки он просто прочитает следующую строку и добавит ее к тому, что уже прочитал. (Осторожно: это может быть не тем, что вы хотите.)Примечание: некоторые версии некоторых оболочек могут рассматривать такие неполные команды как ошибки. В таких случаях (или, фактически, в любом случае, когда у вас длинная команда), вы можете поставить обратную косую черту (
\
) в конце строки, чтобы указать оболочке продолжить чтение команды в другой строке:или же
Как говорит Тердон,
(
и)
может быть использован для группировки команд. Утверждение, что они «на самом деле не имеют отношения к этой дискуссии», является дискуссионным. Некоторые из команд в ответе Тердона могут быть группами команд . Например,Является ли это:
command1
и жди, пока он закончится.command2
и дождитесь ее завершения.Тогда, если
command2
получится,command3
и жди, пока он закончится.command4
и дождитесь ее завершения.Если
command2
не удалось, остановите обработку командной строки.Вне скобок,
|
связывает очень плотно, такэквивалентно
и
&&
и||
крепче;
, такэквивалентно
т.е.
command3
будет выполняться независимо от состояния выходаcommand1
и / илиcommand2
.источник
;
сам по себе (или без предшествующей ему команды) это синтаксическая ошибка, а не пустое выражение. Таким образом; ;
, это ошибка. (Распространенная ошибка для новых пользователей, ИМХО). Также:;;
это специальный разделитель, дляcase
выписок.;
,&&
,||
,&
, и|
, ошибки , если они появляются ни с чем перед ними. Кроме того, Тердон обратился;;
(кратко) в своем ответе.linebreak
токена в грамматике оболочки POSIX. Поэтому, возможно, можно с уверенностью сказать, что все POSIX-совместимые оболочки примут их. Я поддерживаю свое заявление как общий отказ от ответственности; если вы найдете достаточно старую оболочку pre-POSIX, такую как настоящая оболочка Bourne или более старая, все ставки отменяются.