Другое решение sed
:
$ sed -E 's/^([^.]+).*\](.*)/\1\2/' ip.txt
2016-10-24 10:25:48 Found 2735 files (298.6 MB) needing backup
2016-10-24 10:25:48 6.08 GB required (including padding), 1.2 TB available
2016-10-24 10:27:56 Copied 3128 items (283.1 MB) from volume Macintosh HD. Linked 5756.
2016-10-24 10:27:59 Created new backup: 2016-10-24-102758
2016-10-24 10:27:59 Failed to send message because the port couldn't be created.
2016-10-24 10:28:00 Could not back up OS X Recovery to /Volumes/BackupA/Backups.backupdb: Error Domain=NSCocoaErrorDomain Code=-69830 "Failed to get info for unmounted Recovery partition (error -69830): This operation requires an unmounted disk" UserInfo={NSLocalizedDescription=Failed to get info for unmounted Recovery partition (error -69830): This operation requires an unmounted disk}
^ ([^.] +)
захватывает все не .
символов от начала строки . * \]
игнорировать все до последнего ]
в строке (. *)
захватить оставшиеся символы \ 1 \ 2
первая и вторая захваченные группы sed
используют -r
вместо -E
для расширенного параметра регулярного выражения {{ 1}}
sed 's / ^ \ ([^.] \ + \). * \] \ (. * \) / \ 1 \ 2 /'
, если опция расширенного регулярного выражения недоступен Нет, конструкции , если A; затем B; иначе C; fi
и A && B || C
не эквивалентны .
С , если A; затем B; иначе C; fi
, команда A
всегда оценивается и выполняется (по крайней мере, делается попытка ее выполнить), а затем либо команда B
, либо команда C
оценены и выполнены.
С A && B || C
, то же самое для команд A
и B
, но отличается для C
: команда C
оценивается и выполняется, если либо A
не работает , либо B
не работает.
В вашем примере предположим, что вы chmod ur ./myfile
, тогда, несмотря на успешное выполнение [-f ./myfile]
, вы получите cat / home / user / myfile
Мой совет: используйте A && B
или A || B
все, что вам нужно, это легко читать и понимать, и здесь нет ловушек. Но если вы имеете в виду if ... then ... else ... тогда используйте if A; затем B; иначе C; fi
.
Оператор && выполняет следующую команду, если предыдущая команда имела успешное выполнение (возвращенный код выхода ($?) 0 = логическая истина).
В форме A && B || C
, команда (или условие) A оценивается, и если A возвращает истину (успех, код выхода 0), то команда B выполняется.
Если A завершился неудачно (таким образом, будет возвращено false - код выхода отличный от 0) и / или B завершится неудачно (возврат false ), то будет выполнена команда C .
Также оператор &&
используется как AND в проверках условий, а оператор ||
работает как OR при проверках условий.
В зависимости от того, что вы хотите сделать со своим скриптом, сформируйте A && B || C
может использоваться для проверки условий, как в вашем примере, или может использоваться для объединения команд и обеспечения выполнения серии команд, если предыдущие команды имели успешный код выхода 0 .
Вот почему часто встречаются такие команды, как:
do_something && do_something_else_that_depended_on_something
.
Примеры:
apt-get update && apt-get upgrade
Если обновление не удается, обновление не выполняется (имеет смысл в реальном мире ...).
mkdir test && echo "Something"> test / file
Часть echo "Something"
будет выполняться, только если mkdir test
завершился успешно и операция вернула код выхода 0 .
./ configure --prefix = / usr && make && sudo make install
Обычно встречается при компиляции заданий для объединения необходимых зависимых команд в цепочку.
Если вы попытаетесь реализовать вышеуказанные «цепочки» с помощью if - , затем - else , вам понадобится гораздо больше команд и проверок (и, следовательно, больше кода для напишите - еще что-то пошло не так) для простой задачи.
Также имейте в виду, что связанные команды с && и || читаются оболочкой слева направо. Вам может потребоваться сгруппировать команды и проверки условий в скобках, чтобы следующий шаг зависел от успешного вывода некоторых предыдущих команд. Например, см. Это:
root@debian:$ true || true && false;echo $?
1
#read from left to right
#true OR true=true AND false = false = exit code 1=not success
root@debian:$ true || (true && false);echo $?
0
# true OR (true AND false)=true OR false = true = exit code 0 = success
Или пример из реальной жизни:
root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 ]] && [[ $c -eq 2 ]];echo $?
1
#condition $a = true OR condition b = true AND condition $c = false
#=> yields false as read from left to right, thus exit code=1 = not ok
root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 && $c -eq 2 ]];echo $?
0
#vars b and c are checked in a group which returns false,
#condition check of var a returns true, thus true OR false yields true = exit code 0
Имейте в виду, что некоторые команды возвращают разные коды выхода в зависимости от выполняемого процесса или возвращают разные коды в зависимости от своих действий (например, команда GNU diff
, возвращает 1 , если два файла различаются, и 0 в противном случае). С такими командами следует обращаться осторожно в && и || .
Также, чтобы собрать всю головоломку вместе, обратите внимание на конкатенацию команд с использованием оператора ;
. В формате A; B; C
все команды будут выполняться последовательно независимо от кода выхода команды A
и B
.
Большинству людей легче понять форму if
... then
... else
... fi
.
Для a && b || c
, вы должны быть уверены, что b
возвращает истину. Это причина мелких ошибок и хорошая причина избегать этого стиля. Если b не возвращает истину, это не то же самое.
$ if true; then false ; else echo boom ; fi
$ true && false || echo boom
boom
Для очень коротких тестов и действий, в которых нет предложения else, сокращенная длина является привлекательной, например
die(){ printf "%s: %s\n" "$0" "$*" >&2 ; exit 1; }
[ "$#" -eq 2] || die "Needs 2 arguments, input and output"
if [ "$#" -ne 2 ] ; then
die "Needs 2 arguments, input and output"
fi
&&
и ||
являются операторами короткого замыкания
, как только становится известен результат, дальнейшие ненужные тесты пропускаются. a && b || c
сгруппирован как (a && b) || c
. Сначала выполняется a
. Если он терпит неудачу
, что определяется как не возвращающее статус выхода 0, то группа (a && b)
известна как неудачно
и b
запускать не нужно. ||
не знает результат выражения, поэтому необходимо выполнить c
. Если a
завершается успешно (возвращает ноль), тогда оператор &&
еще не знает результат a && b
, поэтому должен выполнить b
] выяснить. Если b
завершается успешно, то a && b
завершается успешно, и ||
знает, что общий результат успешен, поэтому не нужно запускать c
]. Если b
терпит неудачу, то ||
по-прежнему не знает значение выражения, поэтому необходимо запустить c
.
Большая часть путаницы по этому поводу может быть связана с документацией bash, в которой эти И и ИЛИ списки называются. Хотя логически они похожи на &&
и ||
, заключенные в квадратные скобки, они функционируют по-другому.
Некоторые примеры могут лучше всего проиллюстрировать это ...
ПРИМЕЧАНИЕ: одинарные и двойные квадратные скобки (
[...]
и[[...]]
) являются Команды сами по себе, которые выполняют сравнение и возвращают код выхода . На самом деле они не нуждаются вif
.
cmda && cmdb || cmdc
Если cmda
завершается как истина, выполняется cmdb
.
Если cmda
завершается false, cmdb
НЕ выполняется, а cmdc
выполняется.
cmda; cmdb && cmdc || cmdd
Как cmda
завершается, игнорируется.
Если cmdb
завершается как истина, выполняется cmdc
.
Если cmdb
завершается false, cmdc
НЕ выполняется, а cmdd
-.
cmda && cmdb; cmdc
Если cmda
завершается как истина, выполняется cmdb
, за которым следует cmdc
.
Если cmda
завершается как false, cmdb
НЕ выполняется , но cmdc
выполняется.
А? Почему выполняется cmdc
?
Потому что для интерпретатора точка с запятой (;
) и новая строка означают одно и то же. Баш видит эту строку кода как ...
cmda && cmdb
cmdc
Чтобы добиться ожидаемого, мы должны заключить cmdb; cmdc
внутри фигурных скобок, чтобы сделать их составной командой (групповая команда) . Дополнительная завершающая точка с запятой - это просто требование {...; }
синтаксис. Итак, мы получаем ...
cmda && {cmdb; cmdc; }
Если cmda
завершается как истина, выполняется cmdb
, за которым следует cmdc
.
Если cmda
завершается false, ни cmdb
, ни cmdc
не выполняется.
Выполнение продолжается со следующей строки.
Условные списки команд наиболее полезны для как можно более быстрого возврата из функций и, таким образом, избегают интерпретации и выполнения большого количества ненужного кода. Однако множественные возвраты функций означают, что нужно быть навязчивым к тому, чтобы функции были короткими, чтобы было легче обеспечить соблюдение всех возможных условий.
Вот пример из некоторого работающего кода ...
fnInit () {
:
_fn="$1"
### fnInit "${FUNCNAME}" ...
### first argument MUST be name of the calling function
#
[[ "$2" == "--help-all" ]] && { helpAll ; return 0; }
### pick from list of functions
#
[[ "$2" == "--note-all" ]] && { noteAll ; return 0; }
### pick from notes in METAFILE
#
[[ "$2" == "--version" ]] && { versionShow "${_fn}" "${@:3}"; return 0; }
#
[[ "$2" == "--function" ]] && {
isFnLoaded "$3" && { "${@:3}" ; return 0; }
#
errorShow functionnotfound "Unknown function: $3"
return 0
}
### call any loaded function
#
[[ "$2" == "--help" || "$2" == "-h" ]] && { noteShow "$_fn" "${@:3}"; return 0; }
### fnInit "${FUNCNAME}" --help or -h
#
return 1
}