2017-01-04 3 views
0

My Bash-Script должен сделать что-то другое, в соответствии с началом переменной. Когда я запускаю следующий сценарий:Linux bash if - elif не работает должным образом

#!/bin/bash 

line="__B something" 

if [ -n $(echo "$line" | grep "^__A") ]; then 
    echo "Line __A" 
elif [ -n $(echo "$line" | grep "^__B") ]; then 
    echo "Line __B" 
elif [ -n $(echo "$line" | grep "^__C") ]; then 
    echo "Line __C" 
elif [ -n $(echo "$line" | grep "^__D") ]; then 
    echo "Line __D" 
elif [ -n $(echo "$line" | grep "^__E") ]; then 
    echo "Line __E" 
elif [ $(echo "$line" | grep "^__F") ]; then 
    echo -n "Line __F" 
else 
    echo "something other" 
fi 

Bash не признает, что начало строки с __B .:

результат:

Line __A 

Что случилось с моим сценарием? Благодарим за помощь!

+1

это выглядит, как вы неуместны последним ' -n' – Matthias

+3

Используйте больше кавычек! 'if [-n" $ (echo ...) "]; затем'. Процитировать расширение параметра! (но ваш дизайн в целом неплохой). –

+0

@gniourf_gniourf: если вы попытаетесь удвоить цитату команды * whole * 'echo | grep' (а не только снип, которую вы показываете), вы увидите, что это не так просто, особенно учитывая встроенное пространство в' $ line'. – cdarke

ответ

1

Я считаю, что это связано с тонкостями разницы между использованием [[ и [ в bash, если условия.

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

if [[ -n $(echo "$line" | grep "^__A") ]]; then 
    echo "Line __A" 

или вы можете процитировать подоболочку как этот

if [ -n "$(echo '$line' | grep '^__A')" ]; then 
    echo "Line __A" 

[[ имеет меньше сюрпризов и, как правило, безопаснее использовать. Но это не portable - Posix не указывает, что он делает, и только некоторые оболочки поддерживают его (рядом с bash, я слышал, что ksh поддерживает его). Например, вы можете сделать

[[ -e $b ]]

, чтобы проверить, существует ли файл. Но с [ вы должны указать $b, , потому что он разделяет аргумент и расширяет такие вещи, как "a*" (где [[ берет его буквально). Это также связано с тем, как [ может быть внешней программой и получает свой аргумент как обычно, как и любая другая программа (хотя она также может быть встроенной, но тогда она по-прежнему не имеет этой специальной обработки).

в соответствии с this ответ здесь на stackoverflow. Таким образом, в вашем случае, скорее всего, bash разделяет вашу строку на пространстве и имеет некоторые побочные эффекты.

2

Если вы запустите скрипт, используя xtrace вариант, чем вы можете увидеть, что происходит:

bash -x your-script 
+ line='__B something' 
++ echo '__B something' 
++ grep '^__A' 
+ '[' -n ']' 
+ echo 'Line __A' 
Line __A 

Поскольку вы используете старый testвстроенный (иначе известный как [) расширение делается, но не приводит к результатам тестирования, кроме -n. Использование [[ключевое слово правильно процитировать вещи:

bash -x your-script 
+ line='__B something' 
++ echo '__B something' 
++ grep '^__A' 
+ [[ -n '' ]] 
++ echo '__B something' 
++ grep '^__B' 
+ [[ -n __B something ]] 
+ echo 'Line __B' 
Line __B 

Однако, используя внешнюю программу grep является тратой.Последние версии bash имеют регулярные выражения (УЭ) встроенные (с помощью связывания оператора =~), но вам не нужен УЭ в этом случае просто подстановка будет делать:

#!/bin/bash 

line="__B something" 

if [[ $line == __A* ]]; then 
    echo "Line __A" 
elif [[ $line == __B* ]]; then 
    echo "Line __B" 
elif [[ $line == __C* ]]; then 
    echo "Line __C" 
elif [[ $line == __D* ]]; then 
    echo "Line __D" 
elif [[ $line == __E* ]]; then 
    echo "Line __E" 
elif [[ $line == __F* ]]; then 
    echo -n "Line __F" 
else 
    echo "something other" 
fi 
Смежные вопросы