Существует разница в том, как Bash и Dash обрабатывают ввод со стандартного ввода. :При запуске команды(su
здесь )Bash заботится о том, чтобы оставить позицию чтения на стандартном вводе сразу после строки, вызвавшей запуск команды, либо считывая побайтно для каналов, либо возвращаясь назад, если ввод из файла. Dash это не волнует, он просто читает полные блоки.
Это важно, потому что стандартный ввод и позиция чтения в нем совместно используются оболочкой и дочерним процессом.
Таким образом, с Bash он читает su test\nwhoami\n
, выполняет поиск сразу после первой новой строки, затем запускает su
, который теперь видит whoami\n
на входе.
С Dash он читает su test\nwhoami\n
, запускает su
, который не видит ввода и завершает работу, а затем Dash запускает whoami
.
Вы можете видеть то же самое здесь, с Dash, команда date
выполняется и read
получает пустой ввод, а с Bash эта строка от read
до x
.
$ cat test.sh
read x
date
echo "variable x = '$x'"
$ cat test.sh | bash
variable x = 'date'
$ cat test.sh | dash
Sat Aug 24 12:25:23 EEST 2019
variable x = ''
Если я правильно интерпретирую POSIX-описание sh
, требуется осторожное поведение Bash, а более слабый подход Dash не соответствует этому:
STDIN
[...] When the shell is using standard input and it invokes a command that also uses standard input, the shell shall ensure that the standard input file pointer points directly after the command it has read when the command begins execution. It shall not read ahead in such a manner that any characters intended to be read by the invoked command are consumed by the shell
Что бы это ни стоило, оболочка Busybox ведет себя здесь как Dash, все остальные, которые я тестировал, ведут себя так же, как Bash.
Используйте здесь только awk:
gawk -v map='[GI]>H,B>E,[TS ]>C' '
BEGIN { nrf=split(map, tmp, /[,>]/); FIELDWIDTHS="5 5 1 1 4 1 *" }
$4=="A"{ buf= buf $6 }
ENDFILE{
for(i=1; i<=nrf; i+=2) gsub(tmp[i], tmp[i+1], buf);
print buf >FILENAME".output"; close(FILENAME".output"); buf=""
}'./*.dssp
Здесь в -v map='[GI]>H,B>E,[TS ]>C'
мы передаем преобразование отображения символов в awk (, каждый из которых разделен запятой; >
также используется для большей удобочитаемости между каждой группой сопоставления )в качестве переменного параметра.
затем внутри блока BEGIN{} мы разделили отображение, полученное из переменной map
, во временный массивtmp
и рассмотрели эти ,
и >
как разделители; мы также определили поля с помощью FIELDWIDTHS (GNU awk ).
Затем мы проверяем, равно ли 4 е поле символу "A", если да, то буферизуем 6 е поле в режиме добавления из каждой строки вbuff
Переменная.
в конце каждого входного файла мы обрабатываем блок ENDFILE{} (GNU awk ), и здесь мы делаем цикл по сопоставлению пар символов и заменяем левые -символы их правыми -руки в переменной buff
; и после этого мы печатаем обновленное содержимоеbuff
в выходной файл с тем же именем, что и вход, с добавленным суффиксом, например «fileName.output».