У чому різниця між grep apple file
і grep "apple" file
? Що робить розміщення лапок? Вони, як видається, працюють і роблять точно те саме (відображають один і той же рядок).
У чому різниця між grep apple file
і grep "apple" file
? Що робить розміщення лапок? Вони, як видається, працюють і роблять точно те саме (відображають один і той же рядок).
Відповіді:
Лапки впливають на те, які символи ваша оболонка вважає особливими та мають синтаксичне значення. У вашому прикладі це не має значення, оскільки apple
таких символів немає.
Але розглянемо інший приклад: grep apple tree file
буде шукати слово apple
у файлах tree
і file
, тоді як grep "apple tree" file
буде шукати слово apple tree
у файлі file
. Лапки говорять bash, що пробіл слів у "apple tree"
не починає новий параметр, але повинен бути частиною поточного параметра. grep apple\ tree file
дав би той самий результат, тому що \
говорить Баш нехтувати особливим значенням наступного персонажа і ставитися до цього буквально.
"
) та одинарними лапками ( '
). Одиночні лапки перешкоджають інтерпретації певних символів, таких як $
, тоді як подвійні лапки дозволяють інтерпретувати. Наприклад, grep '${USER}'
буде шукати текст ${USER}
, тоді як grep "${USER}"
буде шукати текст, який USER
містить змінна (наприклад johnstacen
).
Подвійні лапки дозволяють оцінити, одиничні цитати запобігають оцінюванню, а жодні лапки не дозволяють розширити підстановку під час використання в командному рядку. Як надумані приклади:
[user@work test]$ ls .
A.txt B.txt C.txt D.cpp
# The following is the same as writing echo 'A.txt B.txt C.txt D.cpp'
[user@work test]$ echo *
A.txt B.txt C.txt D.cpp
[user@work test]$ echo "*"
*
[user@work test]$ echo '*'
*
# The following is the same as writing echo 'A.txt B.txt C.txt'
[user@work test]$ echo *.txt
A.txt B.txt C.txt
[user@work test]$ echo "*.txt"
*.txt
[user@work test]$ echo '*.txt'
*.txt
[user@work test]$ myname=is Fred; echo $myname
bash: Fred: command not found
[user@work test]$ myname=is\ Fred; echo $myname
is Fred
[user@work test]$ myname="is Fred"; echo $myname
is Fred
[user@work test]$ myname='is Fred'; echo $myname
is Fred
Розуміння того, як працюють котирування, має вирішальне значення для розуміння Баша. Наприклад:
# for will operate on each file name separately (like an array), looping 3 times.
[user@work test]$ for f in $(echo *txt); do echo "$f"; done;
A.txt
B.txt
C.txt
# for will see only the string, 'A.txt B.txt C.txt' and loop just once.
[user@work test]$ for f in "$(echo *txt)"; do echo "$f"; done;
A.txt B.txt C.txt
# this just returns the string - it can't be evaluated in single quotes.
[user@work test]$ for f in '$(echo *txt)'; do echo "$f"; done;
$(echo *txt)
Ви можете використовувати одинарні лапки, щоб передати команду через змінну. Одиночні котирування не дадуть оцінювати. Подвійні котирування оцінюватимуть.
# This returns three distinct elements, like an array.
[user@work test]$ echo='echo *.txt'; echo $($echo)
A.txt B.txt C.txt
# This returns what looks like three elements, but it is actually a single string.
[user@work test]$ echo='echo *.txt'; echo "$($echo)"
A.txt B.txt C.txt
# This cannot be evaluated, so it returns whatever is between quotes, literally.
[user@work test]$ echo='echo *.txt'; echo '$($echo)'
$($echo)
Ви можете використовувати одинарні лапки всередині подвійних лапок, а також можете використовувати подвійні лапки всередині подвійних лапок, але подвійні лапки всередині одинарних лапок не слід робити (не уникаючи їх), вони не будуть оцінюватися, вони будуть інтерпретуватися буквально. Одиночні цитати в межах однієї лапки не слід робити (не уникаючи їх).
Вам потрібно буде глибоко зрозуміти котирування, щоб ефективно використовувати Bash. Дуже важливо!
Як правило, я не використовую лапки, якщо хочу, щоб Bash щось розширив на елементи (наприклад, масив), використовую одиничні лапки для буквальних рядків, які не підлягають зміні, і я ліберально використовую подвійні лапки для змінних які можуть повернути будь-який тип рядка. Це потрібно для того, щоб збереглись пробіли та спеціальні символи.
grep a*b equations.txt
то він буде шукатиa*b
, якщо у поточному каталозі не буде файла, який починається з a і закінчується b, у цьому випадку (оскільки (ba) sh розширить назви файлів у командному рядку) grep буде викликаний з повні різні параметри, в результаті чого різні результати. Зазвичай це більше проблеми з find, оскільки така командаfind . -name *.txt
призведе до несподіваної поведінки, якщо в поточному каталозі є файл txt. Краще в цьому випадку використовувати лапки.