2016-12-31 13 views
4

Так у меня есть проблема ниже, но мой вопрос более общий характер - как увидеть точное содержание памяти, на которую ссылаются Баш переменного, чтобы понять, почему они не совпадают:См. Точное содержание переменной bash? (Шестнадцатеричный не помогает)

# [[ $c1 == $c ]] || echo nope 
nope 
# [[ $c1 == "bkup dt" ]] || echo nope 
# [[ $c == "bkup dt" ]] || echo nope 
nope 
# hexdump -C <<<$c 
00000000 62 6b 75 70 20 64 74 0a       |bkup dt.| 
00000008 
# hexdump -C <<<$c1 
00000000 62 6b 75 70 20 64 74 0a       |bkup dt.| 
00000008 
# [ "$c1" = "$c" ] || echo nope 
nope 
# [ ! "$c1" = "$c" ] || echo nope 

Или это похоже на ошибку? Я могу повторить эту проблему с:

$ cd /tmp 
$ mkdir aaa 
$ echo 2 > aaa/1 
$ echo 2 > aaa/2 
$ c=$(ls -A aaa) 
$ [[ $c == $(echo $c) ]] || echo not equal 
not equal 
$ hexdump -C <<<$c 
00000000 31 20 32 0a          |1 2.| 
00000004 
$ hexdump -C <<<$(echo $c) 
00000000 31 20 32 0a          |1 2.| 
00000004 
$ c1="1 2" 
$ [[ $c1 == $(echo $c1) ]] || echo not equal 
$ [[ $c1 == $(echo $c) ]] || echo not equal 
$ [[ $c1 == $c ]] || echo not equal 
not equal 
+0

Вы видите точное соответствие палатки переменной; вы просто получаете * дополнительную * новую строку ('0a'), вызванную этой строкой. 'printf '% s'" $ c "| hexdump -C' пропустит это, если вы не хотите просто игнорировать его. – chepner

ответ

10

Лучше всего, чтобы проверить содержимое переменной является использование declare -p:

$ c="1 2" 
$ declare -p c 
declare -- c="1 2" 

Обратите внимание, что тесты ошибаются, потому что вы теряете котировки в ваши переменные расширения!

Посмотрите:

$ c="1 2" # with two spaces 
$ declare -p c 
declare -- c="1 2" 
$ echo $c 
1 2 
$ echo "$c" 
1 2 
$ d=$(echo $c) 
$ declare -p d 
1 2 

Вы должны указать каждое переменное расширение, , если вы действительно хотите иметь слово расщепление и путь расширение применения к ним! (и, как правило, вы, конечно, не хотите, чтобы это произошло).

Даже с вашей стратегией hexdump вам нужна цитата:

$ c="1 2" # two spaces 
$ hexdump <<< $c 
00000000 31 20 32 0a          |1 2.| 
00000004 
$ hexdump <<< "$c" 
00000000 31 20 20 32 0a         |1 2.| 
00000005 

Что вы испытываете именно это:

$ mkdir aaa; touch aaa/{1,2} 
$ c=$(ls -A aaa) 
$ declare -p c 
declare -- c="1 
2" 
$ # see? there's a new line between the files. 
$ echo $c 
1 2 
$ echo "$c" 
1 
2 
$ # Use quotes! 

Иногда declare -p не будет вполне показать пространства должным образом. В этом случае вы можете использовать printf так:

$ c=$' \n' 
$ declare -p c 
declare -- c="  
" 
$ # there are spaces, but you can't see them 
$ printf '%q\n' "$c" 
$' \n' 

Стратегия DECLARE также хорошо, как вы можете проверить массивы и функции тоже:

$ a=(one two "three four") 
$ declare -p a 
declare -a a='([0]="one" [1]="two" [2]="three four")' 
$ declare -A h=([one]=1 [two]=2) 
$ declare -p h 
declare -A h='([one]="1" [two]="2")' 
$ f() { echo hello; } > somewhere > >(over the rainbow) 
$ declare -pf f 
f() 
{ 
    echo hello 
} > somewhere 2> >(over the rainbow) 
$ # You need also the -f switch to target functions 

У вас также есть доступ к флагам переменные:

$ declare -litux hello=world 
$ declare -p hello 
declare -itx hello="0" 
$ # Have fun! 
+0

yep это точно отвечает на вопрос, не уверен, как я мог бы найти ответ сам, хотя :) – noonex

+0

Обратите внимание, что аргумент для '<<<' * документирован * как не претерпевающий расщепление слов, но на самом деле это не так до 'bash' 4.4. – chepner

+0

С 'c = 'a b'', оба' hd <<< $ a' и 'hd <<<" $ a "' производят тот же вывод в текущей версии bash 4.4. Так что это никому не помогает. – sorontar

0

Вы не видите точное содержание переменной, потому что вы просите bash изменить его. Самый основной эффект в этой команде:

$ echo hello # world 
hello 

$ echo "hello # world" 
hello # world 

Цитирование предотвращает скорлупу от интерпретации специального символа # в качестве стартового символа комментария, и, таким образом, он получает печать.

Пожалуйста read more here

Единственный правильный способ печати переменной точное содержание является процитировать его.

a='a \b 
|c  d' 

Выше, var a получает точную строку, потому что она одинарная.

$ echo "$a" 
a \b 
|c  d 

выше значение вара a точно воспроизведено из-за двойные кавычки.

Как только вы не процитировать расширение переменной $a, вы получите что-то другое:

$ echo $a 
a \b |c d 

Это очень основное требование любой оболочки: квотирование.
И есть одинарные кавычки, двойные кавычки и цитаты с обратной косой чертой.


В вашем случае, чтобы воспроизвести то, что вы видите, вары на самом деле не равны, то они таковы:

$ c='bkup dt 
' 

$ c1='bkup dt' 

То есть, с содержит дополнительный символ новой строки в конце по сравнению с c1 ,

Повторим ваши команды, но правильно цитируя, чтобы увидеть реальное содержимое каждого var (Пожалуйста, обратите внимание, что в пределах [[…]] переменные могут использоваться в большинстве случаев без кавычек).

$ [[ $c1 == $c ]] || echo nope 
nope 

Переменные не равны.

$ [[ $c1 == "bkup dt" ]] || echo nope 

переменная c1 точно равна bkup dt (не выход).

$ [[ $c == "bkup dt" ]] || echo nope 
nope 

Нет, c не совсем «bkup дт» (она имеет дополнительную новую строку).

$ hexdump -C <<<"$c" 
00000000 62 6b 75 70 20 64 74 0a 0a      |bkup dt..| 
00000009 

Обратите внимание на две новые строки в конце, теперь цитируемый переменная воспроизводит его внутреннее значение правильно с добавлением новой строки из <<<.

Сравнить с $c1.

$ hexdump -C <<<"$c1" 
00000000 62 6b 75 70 20 64 74 0a       |bkup dt.| 
00000009 

Только одна новая линия !!.

Может быть, лучший способ будет использовать:

$ printf '%s' "$c" | od -vAn -tx1c 
62 6b 75 70 20 64 74 0a 
    b k u p  d t \n 

Здесь символ новой строки в переменной ясно показано.

Переменная $c1 не показывает, что:

$ printf '%s' "$c1" | od -vAn -tx1c 
62 6b 75 70 20 64 74 
    b k u p  d t 

Команда DECLARE может быть использована также:

$ declare -p c 
declare -- c="bkup dt 
" 

$ declare -p c1 
declare -- c1="bkup dt" 

Как кошки, СЭД и некоторые другие:

$ echo "$c" | cat -vET 
bkup dt$ 
$ 

$ echo "$c1" | cat -vET 
bkup dt$ 

$ echo "$c" | sed -n l 
bkup dt$ 
$ 

$ echo "$c1" | sed -n l 
bkup dt$ 

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


В вашем втором примере также есть новая проблема с строкой.

$ cd /tmp; mkdir aaa; echo 2 > aaa/1; echo 2 > aaa/2 
$ c=$(ls -A aaa) 
$ echo $c | od -vAn -tx1c 
    31 20 32 0a 
    1  2 \n 

В этом случае c, кажется, есть пространство, но то, что он действительно является:

$ echo "$c" | od -vAn -tx1c 
    31 0a 32 0a 
    1 \n 2 \n 

новой строки

Таким образом, эхо также выходит из строя (для пары недостающих котировок, оба они необходимы):

$ echo $(echo $c) | odc 
    31 20 32 0a 
    1  2 \n 

$ echo "$(echo "$c")" | odc 
    31 0a 32 0a 
    1 \n 2 \n