Почему условие не работает, когда я использую его напрямую без переменной?

Может быть проще, если вы используете два sedа. На самом деле, многие вещи так и есть, и они часто быстрее таким образом, по крайней мере, на многоядерных системах.

:    infile =;<<"" \
sed -e's/$/ /;s/hello/&\n\n/g' -e'# marks lines with " $" and splits matches' |
sed -e:n   -e's/ $//;t'  -eG   -e'# sets up a test label, branches for " $"'  \
    -e's/o\n\{20\}$/o world/'  -e'# stacks a byte per match, edits nth match' \
    -e'x;N;x;N;s/\n\n*//;tn'   -e'# completes the stacking; recycles to top'  \
>outfile
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello

hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello world hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello

(С BSD sed вам понадобится буквальная новая строка вместо n для \n эскейпов в правом поле подстановки)

Обычно проще адаптировать поток, чем адаптировать редактор потока. Приведенная выше последовательность делает именно это: она помечает каждую целую строку во входных данных пробелом, но в остальном разделяет выходные строки для каждого вхождения hello. Второй sed затем должен только искать строку, которая не заканчивается пробелом, чтобы знать, что он должен увеличить количество стеков, и затем только явно соответствовать 20-му.

Конечно, это не обязательно должно быть так строго. Можно опустить ведущее o перед \n\{20\}$ и оставить его без замены. Это заменит только от 20-го совпадения до последнего во вводе. Или можно сделать \n\{20,25\}$, чтобы обрабатывать только диапазон совпадений. Или даже: \n\{20,25\}\(\n\{15\}\)*$ для обработки диапазона 20,25 и каждого 10,15-го вхождения после этого.

Вот пример вывода с тем же входом для последнего упомянутого...


hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello world hello world hello world hello world hello world hello world hello hello
hello hello hello hello hello hello hello hello world hello world
hello world hello world hello world hello world hello hello hello hello hello
hello hello hello hello hello world hello world hello world hello world hello world
hello world hello hello hello hello hello hello hello hello
5
06.01.2019, 15:07
3 ответа
if [ $( file -b $i ) == "directory" ]

Здесь две проблемы:

  • Используйте одиночный = для сравнения строк. См. man test для правильного синтаксиса (обратите внимание, что [ во многих случаях имеет реализацию, специфичную для оболочки, поэтому см. Справочную страницу вашей оболочки ), если у вас нет документацию для теста ). Если вам абсолютно необходим == , используйте вместо него [[], что является особенностью многих борновских оболочек, включая bash, ksh, zsh. ПРИМЕЧАНИЕ: хотя == существует в bash , начиная с версии 2.0 , «= следует использовать с командой test для соответствия POSIX». ( страница руководства bash ).

  • Цитируйте все переменные как "$ ()" . Особый интерес представляет $ i . Имена файлов с пробелом разбивают $ i на несколько слов из-за расширения слов оболочки.

Пример:

bash-4.3$ mkdir with\ space
bash-4.3$ i="./with space"
bash-4.3$ set -x
bash-4.3$ [ $( file -b $i ) == "directory" ] && echo "YES"
++ file -b ./with space
+ '[' cannot open '`./with'\''' '(No' such file or 'directory)' cannot open '`space'\''' '(No' such file or 'directory)' == directory ']'
bash: [: too many arguments

name=$( file -b $i )
if [ name == "directory" ]

Здесь проблемы:

  • имя не расширяется до переменной, здесь просто строка «имя». Вам потребуется "$ name" и снова single =

Кроме того, это не могло сработать, поскольку статус выхода test возвращается как false (статус выхода 1)

$ name=$(file -b /etc)
$ set -x
$ [ name == "directory" ]
+ '[' name '==' directory ']'
$ echo $?
+ echo 1
1

Вышеупомянутое тестировалось на оболочках bash и mksh .

4
27.01.2020, 20:32

Пара вопросов:

  • ] указывает на конец аргументов для [ (test), и это должен быть последний аргумент; у вас есть пара ]s, что неправильно; предположительно вы хотели использовать:

    if [ $( file -b $i ) == "directory" ]
    
  • Если бы вы использовали вышеприведенное, то получили бы bash: [: слишком много аргументов], потому что разделение слов было бы сделано на выходе расширения переменной ($i), а затем подстановка команды, $() (команда file) и [ увидит несколько слов перед =, что приведет к сообщению об ошибке. Вам необходимо заключить в кавычки расширение переменной и подстановку команд:

    [ "$(file -b "$1")" == "directory" ]
    

В качестве примечания, вы должны использовать ключевое слово bash [[], а не [, поскольку первое будет обрабатывать разделение слов (и расширение имени пути) за вас.

7
27.01.2020, 20:32

Возникло множество проблем! Давайте возьмем эту часть, которая «работает»:

 name=$( file -b $i )
 if [ name == "directory" ]

Она назначает вывод команды файла переменной с именем name , но не использует ее; вместо этого он запускает команду [ с 3 параметрами: имя , == и каталог . Принятие == - это расширение bash.

Если бы это было исправлено, чтобы использовать $ name вместо name , вы снова получили бы проблему слишком много аргументов во многих случаях. Это связано с тем, что файл возвращает результаты из нескольких слов, например текст ASCII . Итак, после выполнения команды вы получите

if [ ASCII text == directory ]

, и теперь очевидно, что в команде отсутствует некоторая группировка.

if [ "$(file -b -- "$i")" = "directory" ]

- это, вероятно, то, что вам нужно: = , а не == для переносимости и цитирование результата подстановки команд , которую вы почти всегда хотите делать .

4
27.01.2020, 20:32

Теги

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