bash :перебор символов не работает

netstat выполняет обратный поиск в DNS, чтобы отобразить имя хоста вместо IP-адреса. Вы можете отключить обратный поиск DNS с помощью опции -n.

Попробуйте это:

$ sudo netstat -anp
-1
11.04.2021, 09:43
3 ответа

"\n"— это два символа обратной косой черты и строчная буква n.

Теперь в некоторых оболочках echo "\n"будет печатать символ новой строки (два, на самом деле ), и во всех оболочках printf "\n". Но это потому, что echoи printfобращаются с обратной косой чертой особым образом. Это в отличие от, например. C, Perl и Python, где символы обратной косой черты -всегда обрабатываются особым образом в (двойных -кавычках )строк.

Во многих оболочках $'\n'будет строкой, содержащей символ новой строки и ничего больше. (Но в чистом POSIX sh вам понадобится буквальный перевод строки в кавычках.)

Тем не менее, в Bash/Ksh/Zsh вы могли просто проверить строку на соответствие регулярному выражению, а не зацикливаться вручную:

re=$'^[# \n]*$'
if [[ $string =~ $re ]]; then
    echo "string contains only #, space and newline"
fi

(for ((.. ))и ${string:i:j}также не являются стандартными функциями POSIX и не будут работать, например. Dash, который Ubuntu имеет как /bin/sh.)

1
28.04.2021, 22:53

Вы действительно не должны использовать sh (любой вариант, от простого старого sh до bash или ksh или zsh )для выполнения каких-либо операций, кроме самых тривиальных строк или обработки текста. См. Почему использование цикла оболочки для обработки текста считается плохой практикой? по некоторым причинам.

Перебор каждого символа многострочной -строки — это то, что определенно не следует делать в одной оболочке. Это будет ужасно медленно, и вы столкнетесь со всевозможными проблемами с цитированием и концом -из -маркеров строк (, таких как \n), и большинством версий sh (, кроме bash, ksh и zsh )даже не имеют встроенной -поддержки регулярных выражений -, что является, IMO, минимально необходимой функциональностью для обработки текста.

Вместо этого используйте awkили perlили какую-либо другую утилиту/язык обработки текста -.

Например, вы можете заменить весь цикл for на:

echo "$string" | perl -lne 'BEGIN {$c="Yes"; $ec=0};
                            if (!m/^[ #]+$/) { $c="No"; $ec=1; last };
                            END {print $c; exit $ec}'

или

echo "$string" | awk -v c="Yes" -v ec=0 \
                     '!/^[ #]*$/ { c="No"; ec=1; nextfile };
                      END { print c; exit ec}'

Для этого требуется GNU awk (или другой awk, поддерживающийnextfile). В других версиях awk следующее будет работать -, но немного медленнее, потому что не выходит из цикла сразу при плохом совпадении:

echo "$string" | awk -v c="Yes" -v ec=0 \
                     '!/^[ #]*$/ { c="No"; ec=1 };
                      END { print c; exit ec}'

Как должно быть очевидно,это все один и тот же сценарий, просто переписанный немного по-разному для разных синтаксисов perl и awk.

Регулярное выражение, используемое как в perl, так и в awk выше, равно /^[ #]*$/, инвертировано с помощью !. Это соответствует любой строке, которая не содержит только пробелы или хэши.

Все три из них возвращают код выхода 0 при подтвержденном -хорошем вводе и 1 при плохом совпадении. Это можно проверить в sh с помощью переменной $?:

if [ $? -eq 1 ] ; then
   : # string has bad characters, do something!
fi

Вы также можете использовать простой скрипт GNU sed:

echo "$string" | sed -n -e '/[^ #]/q1'
if [ $? -eq 0 ] ; then echo "Yes" else echo "No" ; fi

Код выхода для командыq(quit )является расширением GNU для sed, поэтому требуется GNU sed.

Или, как указал @Isaac, вы можете использовать опцию grep-q(или --quiet/ --silent). Это подавляет нормальный вывод и возвращает только код выхода. Например:

echo "$string" | grep -q '[^ #]'
if [ $? -eq 0 ] ; then echo "Yes" else echo "No" ; fi
1
28.04.2021, 22:53

Как указывали другие, "\n"- это не новая строка, а просто строка с \и nв ней.

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

Можно и так:

case $string in
    (*[![:space:]#]*)
        echo 'other characters in string'
        ;;
    (*)
        echo 'only space-like characters or hashes in string'
esac

или так (вbash):

if [[ $string == *[![:space:]#]* ]]; then
        echo 'other characters in string'
else
        echo 'only space-like characters or hashes in string'
fi

Здесь [:space:]я использовал класс символов POSIX, который будет соответствовать всем видам пробелов, -например, символам, включая пробел, вкладки (различных типов ), каретку -возврат и новая строка. Шаблон *[![:space:]#]*будет соответствовать любой строке, содержащей символ, который является , а не символом, подобным пробелу -, или символом #.

Если вы хотите ввести более строгие ограничения, например, запретив табуляцию или возврат каретки -, тогда используйте $'*[! \n#]*'в качестве шаблона вbash:

pattern=$'*[! \n#]*'
if [[ $string == $pattern ]]; then
        echo 'other characters in string'
else
        echo 'only spaces, hashes, or newlines in string'
fi

Или в стандартной shоболочке:

pattern='*[!
 #]*'

case $string in
    ($pattern)
        echo 'other characters in string'
        ;;
    (*)
        echo 'only spaces, hashes, or newlines in string'
esac
1
28.04.2021, 22:53

Теги

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