Bash: не может убежать переданный по каналу, “в то время как считано” цикл; работы замены процесса

Проверьте файл/etc/ttys, который содержит список терминалов. Только отмеченные "безопасный" позволят корню входить в систему. По умолчанию это - консоль и все виртуальные терминалы. Псевдотерминалы не позволяют корневой вход в систему.

Кроме того, в этот день и возраст, где безопасность является большим беспокойством, я могу спросить, почему Вы все еще используете небезопасный протокол как telnet и не ssh?

(редактирование) благодаря James, я понял, что замял FreeBSD и предложил решение, которое я всегда использовал и считал само собой разумеющимся на Linux. Если у Вас нет дополнения безопасности PAM, включил, у Вас не будет этого файла. Вместо этого используйте файл, упомянутый James на ответе выше.

6
07.11.2014, 07:12
2 ответа

Это можно сделать полностью внутри оболочки с помощью конструкции case .

string='Fox juMPed the rock'
case "$string" in
  *[:lower:]*) echo "The string contains lowercase letters.";;
esac

Для преобразования последовательности в верхний регистр можно использовать typeset -u . Неважно, был ли оригинал полностью в верхнем регистре или нет.

string='Fox juMPed the rock'
typeset -u string
echo "SHOUTING: $string"

Если вы хотите обработать файл, вы можете использовать функцию awk и touppper для преобразования последовательности в верхний регистр. Можно проверить, что s уже имеет верхний регистр с s = = toupper (s) , хотя можно также использовать toupper (s) независимо от того, как.

-121--146223-

Просто перечислите оба узоров, если вы хотите сопоставить файлы, соответствующие любому из образца, то есть файлы, соответствующие * .txt , и файлы, соответствующие * .csv , или, другими словами, файлы, соответствующие * .txt или * .csv . (Вложение квантификаторов и логических операторов имеет значение!)

rm *.txt *.csv

Обратите внимание, что если любой образец не совпадает ни с одним файлом, он останется нетронутым, поэтому rm пожалуется, что не может найти файл с именем * .txt или * .csv . Обычным способом избежать жалобы является использование rm -f , которое бесшумно игнорирует несуществующие файлы.

rm -f *.txt *.csv

Отсутствует оператор для сопоставления последовательностей, соответствующих шаблону 1 и образцу 2. В этом случае в любом случае нет последовательности, совпадающего с * .txt и * .csv .

В ksh образца @ (* .txt | * .csv) или *. @ (txt 'csv) соответствует последовательностям, соответствующим * .txt или * .csv . Этот образец можно использовать в bash, если сначала запустить shopt -s extglob ; Его можно использовать в формате zsh, если сначала выполняется setopt ksh_glob, или можно использовать собственный синтаксис zsh *. (txt 'csv) . Обратите внимание, что если нет файла, соответствующего составному образцу, он будет передан команде как есть. В ATT ksh (и только в ATT ksh, но не в mksh, bash или zsh) можно использовать ~ (N) *. @ (txt 'csv) для расширения до пустого списка, если файл не соответствует образцу. Необходимо использовать rm -f , чтобы не было жалоб на отсутствующий аргумент.

rm -f ~(N)*.@(txt|csv)

В bash сначала запустите shopt -s nullglob , чтобы все узоры расширились до пустого списка, если они ничего не соответствуют.

shopt -s nullglob extglob; rm -f *.@(txt|csv)

В zsh используйте квалификатор N glob или сначала запустите setopt nullglob .

rm -f *.(txt|csv)(N)
setopt nullglob extglob; rm -f *.@(txt|csv)
-121--161373-

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

Чтобы понять, рассмотрим:

inotifywait -qm -e create . | while read line; do echo $line; break; done

Когда read считывает строку, она повторяется, а затем break выполняется и последний процесс завершается. Первый процесс, однако, продолжается до тех пор, пока не произойдет сбой записи в stdout. Таким образом, цикл будет продолжаться, по крайней мере, до тех пор, пока inotifywait не попытается записать свою вторую строку вывода. Из-за капризов буферизации этого может не произойти даже тогда.До обнаружения может потребоваться несколько строк. При неудачной попытке записи выдается SIGPIPE.

Рассмотрим другой случай:

while read line; do echo $line; break; done < <(inotifywait -qm -e create .)

Здесь нет конвейера. При выполнении break выполняется цикл во время .

Документация

Из раздела «Трубопроводы» man bash :

Оболочка ожидает завершения всех команд в трубопроводе...

Это поведение является выбором, сделанным bash . Она не предусмотрена POSIX. POSIX указывает:

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

10
27.01.2020, 20:23
В работе
strace tail -f -n 5000 /var/log/messages | 
    while read line; do echo $line; break; done;

подробно показано, что происходит:

[...]
write(1, "Nov  1 22:20:01 inno systemd[1]:"..., 4096) = 4096

, т.е. хвост записывает в трубопровод сразу до 4096 байт (это то, что трубопровод может буферировать). Обычно для tail вообще не так много данных:

strace tail -f /var/log/messages | while read line; do echo $line; break; done;

показывает

write(1, "Nov  7 07:00:02 inno systemd[1]:"..., 730) = 730

Таким образом tail не будет пытаться записать снова, пока что-нибудь не будет добавлено в файл.

Я думал, что unbuffer решит эту проблему. Удивительно, что это не так.

unbuffer tail -f file1 | while read line; do echo $line; break; done
2
27.01.2020, 20:23

Теги

Похожие вопросы