Каковы операторы управления и перенаправления оболочки?

Каковы операторы управления и перенаправления оболочки?

Я часто вижу в сети руководства, которые связывают различные команды с различными символами. Например:

command1 |  command2
command1 &  command2
command1 || command2    
command1 && command2

Другие, похоже, связывают команды с файлами:

command1  > file1
command1  >> file1

Что это за штуки? Как они называются? Что они делают? Их еще больше?


Мета-тред по этому вопросу..

решение1

Они называются операторами оболочки и да, их больше. Я дам краткий обзор наиболее распространенных из двух основных классов,операторы управленияиоператоры перенаправленияи как они работают по отношению к оболочке bash.

А. Операторы управления

Определение POSIX

В языке команд оболочки — токен, выполняющий функцию управления.
Это один из следующих символов:

&   &&   (   )   ;   ;;   <newline>   |   ||

И |&в Баше.

А !естьнетоператор управления, ноЗарезервированное слово. Он становится логическим НЕ [оператором отрицания] внутриАрифметические выраженияи внутри тестовых конструкций (при этом все еще требуется разделитель-пробел).

A.1 Список терминаторов

  • ;: Выполняет одну команду после завершения другой, независимо от результата первой.

      command1 ; command2
    

Сначала command1он запускается на переднем плане, а после завершения работы command2будет запущен.

Перевод строки, который не находится в строковом литерале или после определенных ключевых слов,нетэквивалент оператора точки с запятой. Список ;разделенных простых команд все еще являетсясписок- как в синтаксическом анализаторе оболочки, он должен продолжать считывать простые команды, которые следуют за ;разделительной простой командой, перед выполнением, тогда как новая строка может ограничивать весь список команд - или список списков. Разница тонкая, но сложная: учитывая, что у оболочки нет предыдущего императива для считывания данных после новой строки, новая строка отмечает точку, в которой оболочка может начать оценивать простые команды, которые она уже считывала, тогда как точка ;с запятой этого не делает.

  • &: Это запустит команду в фоновом режиме, что позволит вам продолжить работу в той же оболочке.

       command1 & command2
    

Здесь command1запускается в фоновом режиме и command2начинает работать на переднем плане немедленно, не дожидаясь command1выхода.

Перевод строки после command1него необязателен.

A.2 Логические операторы

  • &&: используется для построения списков 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

A.3 Оператор трубы

  • |: Оператор конвейера, он передает вывод одной команды в качестве ввода другой. Команда, созданная из оператора конвейера, называетсятрубопровод.

       command1 | command2
    

    Любые выходные данные, напечатанные с помощью , command1передаются в качестве входных данных command2.

  • |&: Это сокращение для 2>&1 |в bash и zsh. Он передает как стандартный вывод, так и стандартную ошибку одной команды в качестве ввода для другой.

      command1 |& command2
    

A.4 Другие знаки препинания в списке

;;используется исключительно для обозначения концазаявление по делу. Ksh, bash и zsh также поддерживают ;&переход к следующему случаю и ;;&(не в ATT ksh) продолжение и тестирование последующих случаев.

(и )привыкли кгрупповые командыи запускать их в подоболочке. {а }также группировать команды, но не запускать их в подоболочке. Смотретьэтот ответдля обсуждения различных типов скобок, квадратных и фигурных скобок в синтаксисе оболочки.

B. Операторы перенаправления

Определение POSIX оператора перенаправления

В языке команд оболочки — токен, выполняющий функцию перенаправления. Это один из следующих символов:

<     >     >|     <<     >>     <&     >&     <<-     <>

Они позволяют вам контролировать ввод и вывод ваших команд. Они могут появляться в любом месте внутри простой команды или следовать за командой. Перенаправления обрабатываются в порядке их появления, слева направо.

  • <: Вводит команду.

      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будет добавлен к нему, после того, что уже в нем есть. Если не существует, то будет создан.

  • >&: (согласно спецификации POSIX) в окружениицифры( 1>&2) или -с правой стороны ( 1>&-) либо перенаправляет толькоодиндескриптор файла или закрывает его ( >&-).

A >&, за которым следует номер дескриптора файла, является переносимым способом перенаправления дескриптора файла, а также >&-переносимым способом закрытия дескриптора файла.

Если справа от этого перенаправления находится файл, пожалуйста, прочтите следующую запись.

  • >&, &>, >>&и &>>: (см. также выше) Перенаправить стандартную ошибку и стандартный вывод, заменив или добавив соответственно.

      command &> out.txt
    

Стандартная ошибка и стандартный вывод commandбудут сохранены в out.txt, перезаписав его содержимое или создав его, если он не существует.

    command &>> out.txt
 

То же, что и выше, за исключением того, что если существует, то к нему будут добавлены out.txtвывод и ошибка .command

Вариант &>происходит из bash, а >&вариант происходит из csh (десятилетиями ранее). Они оба конфликтуют с другими операторами оболочки POSIX и не должны использоваться в переносимых shскриптах.

  • <<: Документ here. Часто используется для печати многострочных строк.

       command << WORD
           Text
       WORD
    

    Здесь, commandбудет принимать все, пока не найдет следующее вхождение WORD, Textв примере выше, как входные данные . Хотя WORDчасто EoFили его вариации, это может быть любая буквенно-цифровая (и не только) строка, которая вам нравится. Когда любая часть WORDзаключена в кавычки или экранирована, текст в документе here обрабатывается буквально, и никакие расширения не выполняются (например, для переменных). Если он не заключен в кавычки, переменные будут расширены. Для получения более подробной информации см.руководство по 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

Несколько других операторов ( >&-, x>&y x<&y) могут использоваться для закрытия или дублирования файловых дескрипторов. Подробности о них см. в соответствующем разделе руководства вашей оболочки (здесьнапример для bash).

Это касается только наиболее распространенных операторов оболочек типа Bourne. Некоторые оболочки имеют несколько дополнительных собственных операторов перенаправления.

Ksh, bash и zsh также имеют конструкции <(…), >(…)и =(…)(последняя zshтолько в). Это не перенаправления, азамена процесса.

решение2

Предупреждение относительно '>'

Начинающие пользователи Unix, которые только что узнали о перенаправлении ввода-вывода ( <и >), часто пытаются делать что-то вроде

командавходной_файл>тот же_файл

или

команда… <файл     >тот же_файл

или, почти то же самое,

котфайл|команда… >тот же_файл

( grep, sed, cut, sortи spellявляются примерами команд, которые люди склонны использовать в подобных конструкциях.) Пользователи с удивлением обнаруживают, что эти сценарии приводят к тому, что файл становится пустым.

Нюанс, который, кажется, не упомянут в другом ответе, можно обнаружить в первом предложенииПеренаправлениеразделбаш(1):

Перед выполнением команды ее входные и выходные данные могут бытьперенаправлено с использованием специальной нотации, интерпретируемой оболочкой.

Первые пять слов должны быть выделены жирным шрифтом, курсивом, подчеркнуты, увеличены, мигать, окрашены в красный цвет и отмечены значком восклицательный знак в красном треугольнике, чтобы подчеркнуть тот факт, что оболочка выполняет запрошенное перенаправление(я). до выполнения команды. И помните также

Перенаправление вывода приводит к открытию файла … для записи …. Если файл не существует, он создается; если существует, он усекается до нулевого размера.

  1. Итак, в этом примере:

    sort roster > roster
    

    оболочка открывает rosterфайл для записи, обрезая его (т.е. отбрасывая все его содержимое), прежде чем sortпрограмма начнет работать. Естественно, ничего нельзя сделать, чтобы восстановить данные.

  2. Можно было бы наивно ожидать, что

    tr "[:upper:]" "[:lower:]" < poem > poem
    

    может быть лучше. Поскольку оболочка обрабатывает перенаправления слева направо, она открывается poemдля чтения (для trстандартного ввода ) до того, как откроет его для записи (для стандартного вывода). Но это не помогает. Несмотря на то, что эта последовательность операций дает два дескриптора файла, они оба указывают на один и тот же файл. Когда оболочка открывает файл для чтения, его содержимое все еще там, но оно все равно затирается до того, как программа будет выполнена. 

Так что же с этим делать?

Решения включают в себя:

  • Проверьте, имеет ли программа, которую вы запускаете, собственную внутреннюю возможность указывать, куда направляется вывод. Это часто обозначается токеном -o(или --output=). В частности,

    sort -o roster roster
    

    примерно эквивалентно

    sort roster > roster
    

    за исключением того, что в первом случае sortпрограмма открывает выходной файл. И она достаточно умна, чтобы не открывать выходной файл, покапослеон прочитал все входные файлы.

    Аналогично, по крайней мере, некоторые версии sedимеют -i(редактироватьяn-место) опция, которая может быть использована для записи выходных данных обратно во входной файл (опять же,послевсе входные данные были прочитаны). Редакторы, такие как ed/ ex, emacs, pico, и vi/ vim позволяют пользователю редактировать текстовый файл и сохранять отредактированный текст в исходном файле. Обратите внимание, что ed(по крайней мере) может использоваться неинтерактивно.

    • viимеет связанную функцию. Если вы введете , он запишет содержимое буфера редактирования в:%!commandEntercommand, прочитать вывод и вставить его в буфер (заменив исходное содержимое).
  • Простой, но эффективный:

    командавходной_файл>временный_файл  && мввременный_файл входной_файл

    Это имеет тот недостаток, что еслиinput_fileссылка, она (вероятно) будет заменена отдельным файлом. Кроме того, новый файл будет принадлежать вам, с защитой по умолчанию. В частности, это несет риск того, что файл станет доступным для чтения всем, даже если исходныйinput_fileне было.

    Вариации:

    • commandinput_file > temp_file && cp temp_file input_file && rm temp_file
      который все равно (потенциально) оставитtemp_fileЧитаемый во всем мире. Еще лучше:
    • cp input_file temp_file && commandtemp_file > input_file && rm temp_file
      Они сохраняют статус ссылки, владельца и режим (защиту) файла, что может привести к удвоению объема ввода-вывода. (Возможно, вам придется использовать опцию вроде -aили -pon cp , чтобы указать, что атрибуты нужно сохранять.)
    • commandinput_file > temp_file &&
      cp --attributes-only --preserve=all input_file temp_file &&
      mv temp_file input_file
      (разбито на отдельные строки только для удобства чтения) Это сохраняет режим файла (и, если вы являетесь пользователем root, владельца), но делает его владельцем вас (если вы не являетесь пользователем root) и создает новый, отдельный файл.
  • Этот блог («Редактирование файлов на месте») предлагает и объясняет

    { рмвходной_файл  &&  команда… >входной_файл; } <входной_файл

    Для этого необходимо, чтобыcommandиметь возможность обрабатывать стандартный ввод (но почти все фильтры могут). Сам блог называет это рискованным ляпом и не рекомендует его использовать. И это также создаст новый, отдельный файл (ни с чем не связанный), принадлежащий вам и с правами доступа по умолчанию.

  • В пакете moreutils есть команда с названием sponge:

    командавходной_файл| губкатот же_файл

    Видетьэтот ответЧтобы получить больше информации.

Вот что стало для меня полной неожиданностью: синтаксическая ошибка говорит:

[Большинство этих решений] не будут работать в файловой системе, доступной только для чтения, где «доступ только для чтения» означает, что ваш$HOME волябыть доступным для записи, но /tmpбудеттолько для чтения(по умолчанию). Например, если у вас Ubuntu, и вы загрузились в Recovery Console, это обычно так. Кроме того, оператор here-document <<<также не будет работать там, так как он требует, /tmpчтобычитай пиши поскольку он также запишет туда временный файл.
(ср.этот вопросвключает в себя straceвывод 'd)

В этом случае может сработать следующее:

  • Только для продвинутых пользователей: Если ваша команда гарантированно выдаст тот же объем выходных данных, что и входные (например, sortилиtr безвариант -dили -s), вы можете попробовать
    командавходной_файл| дд из=тот же_файлconv=notrunc
    Видетьэтот ответ иэтот ответдля получения дополнительной информации, включая объяснение вышеизложенного, а также альтернатив, которые работают, если ваша команда гарантированно выдает тот же объем выходных данных, что и входные данныеили менее(например, grep, или cut). Эти ответы имеют то преимущество, что они не требуют никакого свободного места (или требуют очень мало). Ответы выше формы явно требуют, чтобы было достаточно свободного места для того, чтобы система могла одновременно хранить весь входной (старый) файл и выходной (новый) файл; это неочевидно верно и для большинства других решений (например, и ). Исключение: вероятно, потребует много свободного места, поскольку должен прочитать все свои входные данные, прежде чем сможет записать какие-либо выходные данные, и он, вероятно, буферизует большую часть, если не все эти данные, во временном файле.commandinput_file > temp_file && …sed -ispongesort … | dd …sort
  • Только для продвинутых пользователей:
    командавходной_файл1<>тот же_файл
    может быть эквивалентно ответу ddвыше. Синтаксис открывает указанный файл в дескрипторе файлаn<> filen для входа и выхода, без усечения — своего рода комбинация и . Примечание: некоторые программы (например, и ) могут отказаться запускаться в этом сценарии, поскольку они могут определить, что входные и выходные данные — это один и тот же файл. Смотритеn<n>catgrepэтот ответ для обсуждения вышеизложенного и скрипта, который заставляет этот ответ работать, если ваша команда гарантированно выдает тот же объем выходных данных, что и входныхили менее.
    Предупреждение: я не тестировал сценарий Питера, поэтому не ручаюсь за него.

Так в чем же был вопрос?

Это популярная тема на U&L; она рассматривается в следующих вопросах:

… и это не считая Super User или Ask Ubuntu. Я включил большую часть информации из ответов на вопросы выше в этот ответ, но не всю. (Т.е. для получения дополнительной информации прочтите вопросы выше и ответы на них.)

P.S. У меня естьнетпринадлежность к блогу, который я процитировал выше.

решение3

Больше наблюдений по ;, &, (и)

  • Обратите внимание, что некоторые команды в ответе terdon могут быть нулевыми. Например, вы можете сказать

    command1 ;
    

    (без command2). Это эквивалентно

    command1
    

    (т.е. он просто работает command1на переднем плане и ждет завершения. Для сравнения,

    command1 &
    

    (без command2) запустится command1в фоновом режиме и немедленно выдаст еще одно приглашение оболочки.

  • Напротив, command1 &&, command1 ||, и command1 |не имеют никакого смысла. Если вы введете один из них, оболочка (вероятно) предположит, что команда продолжается на другой строке. Она отобразит вторичное (продолжение) приглашение оболочки, которое обычно установлено на >, и продолжит чтение. В сценарии оболочки она просто прочитает следующую строку и добавит ее к тому, что уже прочитала. (Осторожно: это может быть не то, что вы хотите.)

    Примечание: некоторые версии некоторых оболочек могут считать такие неполные команды ошибками. В таких случаях (или, по сути, влюбой(в случае, если у вас длинная команда), вы можете поставить обратную косую черту ( \) в конце строки, чтобы указать оболочке продолжить чтение команды на другой строке:

    command1  &&  \
    command2
    

    или

    find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \
                            -newer some_existing_file -user fred -readable -print
    
  • Как говорит terdon, (и )можно использовать для группировки команд. Утверждение, что они «не имеют особого отношения» к этой дискуссии, спорно. Некоторые из команд в ответе terdon могут быть командойгруппы. Например,

    ( command1 ; command2 )  &&  ( command3; command4 )
    

    Означает ли это:

    • Запустите command1и дождитесь окончания.
    • Затем, независимо от результата выполнения первой команды, запустите ее command2и дождитесь ее завершения.
    • Тогда, если это command2удастся,

      • Запустите command3и дождитесь окончания.
      • Затем, независимо от результата выполнения этой команды, запустите ее command4и дождитесь ее завершения.

      В случае command2неудачи прекратите обработку командной строки.

  • Вне скобок |связывает очень крепко, поэтому

    command1 | command2 || command3
    

    эквивалентно

    ( command1 | command2 )  ||  command3
    

    и &&и ||свяжите крепче, чем ;, так что

    command1 && command2 ; command3
    

    эквивалентно

    ( command1 && command2 ) ;  command3
    

    т.е. command3будет выполнено независимо от статуса выхода command1и/или command2.

Связанный контент