Важным флагом является флаг «выполнения» в каталоге,который в каталогах на самом деле является «проходимым» флагом. Если он не установлен, каталог нельзя использовать в пути. Таким образом, :1 )вы не можете использовать компакт-диск, а 2 )вы не можете использовать файлы в каталоге.
Давайте настроим тестовый ритг с каталогом и файлом
>>mkdir listonly
>>touch listonly/uselessfile
Пока все хорошо:
>>ls listonly/
uselessfile
Изменить исполняемый флаг каталога:
>>chmod -x listonly
Вы больше не можете сделать перезарядку:
>>cd listonly
bash: cd: listonly: Permission denied
При использовании ls
вы можете видеть файлы:
>>ls listonly/
uselessfile
Однако во многих случаях ls
имеет псевдоним для добавления некоторых опций, требующих просмотра метаданных для каждого файла (флаги, отметка времени, размер... ), чего он не может сделать, поскольку для этого требуется использование каталог в пути (для меня, который был ls --color=auto'
), поэтому вы должны использовать обычный ls
, иначе вы получите файлы, но с неприглядными ошибками:
>>ls listonly/
ls: cannot access 'listonly/uselessfile': Permission denied
uselessfile
Обратите внимание, что файловые менеджеры обычно меняют свой рабочий каталог на целевой каталог, чтобы просмотреть его содержимое, поэтому это может не очень хорошо работать с графическими интерфейсами.
Вы можете разделить строку на отдельные символы:
string=11111001
echo "$string" | grep -o.
и прочитать их как массив:
readarray -t arr <<<"$(grep -o. <<<"$string")"
Тогда, конечно, каждый символ будет находиться в каждом индексе массива arr
.
$ declare -p arr
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")
Но зачем создавать новый массив, если bash может обращаться к каждому отдельному символу напрямую, как это:
$ string=11111001
echo "${string:5:1}" "${string:7:1}"
0 1
Читайте о ${parameter:offset:length}
в man bash
.
string=11111001
read -a array <<< $(echo "$string" | sed 's/./& /g')
sed
для разделения строки пробелами.
Более подробный способ чтения строки по одному символу за раз:
string=11111001
arr=()
while IFS= read -r -d "" -n 1 char; do
arr+=("$char")
done < <(printf '%s' "$string")
declare -p arr
выходы
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")
Для полноты, с zsh
, чтобы разбить строку на:
chars=( ${(s[])string} )
(если $string
содержит байты, не являющиеся частями допустимых символов, каждый из них все равно будет храниться как отдельные элементы)
вы можете сделать то же самое, но предварительно сняв многобайтовую опцию, например, локально в анонимной функции:
(){ set -o localoptions +o multibyte
bytes=( ${(s[])string} )
}
Вы можете использовать возможности PCRE для их сопоставления с\X
:
zmodload zsh/pcre
(){
graphemes=()
local rest=$string match
pcre_compile -s '(\X)\K.*'
while pcre_match -v rest -- "$rest"; do
graphemes+=($match[1])
done
}
(предполагается, что ввод содержит текст, правильно закодированный в шармапе локали ).
С string=$'Ste\u0301phane'
те дают:
chars=( S t e ́ p h a n e )
bytes=( S t e $'\M-L' $'\M-\C-A' p h a n e )
graphemes=( S t é p h a n e )
Поскольку графемный кластер e
+ U+0301 (, который устройства отображения обычно представляют так же, как и предварительно составленный эквивалент é
U+00E9, )состоит из 2 символов (U+0065 и U+0301 ), где в локалях, использующих UTF -8 в качестве своего шармапа, первый кодируется одним байтом (0x65 ), а второй — двумя байтами (0xcc 0x81, также известный как Мета -L и Мета -Ctrl -A ).
Для строк, состоящих только из символов ASCII, таких как 11111001
, все три будут эквивалентны.
Обратите внимание, что в zsh
, как и во всех других оболочках, кроме ksh/bash, индексы массива начинаются с 1, а не с 0.
В bash
4.4+, поскольку bash
в любом случае не может хранить символы NUL в своих переменных, вы можете вызвать другую утилиту, чтобы выполнить разбиение и распечатать результат NUL -с разделителями, который вы можете прочитать в массив с readarray -td ''
.
Если ваша система поставляется с реализацией GNU grep
, вы можете сделать:
readarray -td '' bytes < <(printf %s "$string" | LC_ALL=C grep -zo.)
readarray -td '' chars < <(printf %s "$string" | grep -zo.)
readarray -td '' graphemes < <(printf %s "$string" | grep -zPo '\X')
Все, кроме первого, будут пропускать байты, которые не являются частью допустимых символов в локали (по крайней мере с GNU grep
3.4 ). Например, сstring=$'Ste\u0301phane \\\xf0\x80z.'
(замыкающая часть не образует действительного UTF -8 )в локали UTF -8, что дает:
declare -a bytes=([0]="S" [1]="t" [2]="e" [3]=$'\314' [4]=$'\201' [5]="p" [6]="h" [7]="a" [8]="n" [9]="e" [10]=" " [11]="\\" [12]=$'\360' [13]=$'\200' [14]="z" [15]=".")
declare -a chars=([0]="S" [1]="t" [2]="e" [3]="́" [4]="p" [5]="h" [6]="a" [7]="n" [8]="e" [9]=" " [10]="\\" [11]="z" [12]=".")
declare -a graphemes=([0]="S" [1]="t" [2]="é" [3]="p" [4]="h" [5]="a" [6]="n" [7]="e" [8]=" " [9]="\\" [10]="z" [11]=".")
Если не в системе GNU и предполагается, что $string
содержит допустимый текст UTF -8, вместо этого можно использовать perl
:
readarray -td '' bytes < <(perl -0le 'print for split "", shift' -- "$string")
readarray -td '' chars < <(perl -CSA -0le 'print for split "", shift' -- "$string")
readarray -td '' graphemes < <(perl -CSA -0le 'print for shift =~ /\X/g' -- "$string")
Использование Raku (, ранее известного как Perl _6):
~$ OLDIFS="$IFS"
~$ IFS=" "
~$ string=11111001
~$ read -a array <<< "$(raku -e lines.comb.print <<<"$string")"
~$ declare -p array
declare -a array='([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")'
~$ IFS="$OLDIFS"
~$ echo -n "$IFS" | raku -e 'dd($*IN.slurp);'
" \t\n"
Юникод в Раку:
Согласно документам, «Raku применяет нормализацию по умолчанию ко всему вводу и выводу, за исключением имен файлов, которые читаются и записываются как UTF8 -C8; графемы, которые являются пользовательскими -видимыми формами символов, будет использовать нормализованное представление." Таким образом, приведенный ниже код/символы дают следующие результаты:
~$ OLDIFS="$IFS"
~$ IFS=" "
~$ string1="palmarés,Würdigung,Témoignages d'honneur"
~$ read -a array1a <<< "$(raku -e lines.subst\(/"\s"/,「_」\).split\(「,」\).print <<<"$string1")"
~$ echo "${array1a[@]}"
palmarés Würdigung Témoignages_d'honneur
~$ declare -p array1a
declare -a array1a='([0]="palmarés" [1]="Würdigung" [2]="Témoignages_d'\''honneur")'
~$ read -a array1b <<< "$(raku -e lines.comb.print <<<"${array1a[2]}")"
~$ echo "${array1b[@]}"
T é m o i g n a g e s _ d ' h o n n e u r
~$ declare -p array1b
declare -a array1b='([0]="T" [1]="é" [2]="m" [3]="o" [4]="i" [5]="g" [6]="n" [7]="a" [8]="g" [9]="e" [10]="s" [11]="_" [12]="d" [13]="'\''" [14]="h" [15]="o" [16]="n" [17]="n" [18]="e" [19]="u" [20]="r")'
~$ IFS="$OLDIFS"
~$ echo -n "$IFS" | raku -e 'dd($*IN.slurp);'
" \t\n"
https://docs.raku.org/language/unicode#Normalization
https://github.com/MoarVM/MoarVM/blob/master/docs/strings.asciidoc
[код протестирован на:GNU bash, версия 3.2.57 (1 )-выпуск (x86 _64 -яблоко -darwin14 ]
РЕДАКТИРОВАТЬ _1:«Правильный» способ обработки строк со встроенными переводами строк, по-видимому, состоит в том, чтобы проглотить строку вместо чтения с флагом командной строки Raku ne
, т.е. raku -e slurp.comb.print
вместо raku -ne.comb.print
. Затем $IFS
можно настроить для создания массива с использованием (или игнорированием )новых строк.
РЕДАКТИРОВАТЬ _2:Как отметили @StephaneChazelas и @roaima, звездочки(*
с )проблематичны из-за подстановки файла -. Вот код, показывающий, что цитата здесь (и выше )является правильной:
~$ string_star="*11111001"
~$ echo "$string_star"
*11111001
~$ read -a array_star <<< "$(raku -e slurp.comb.print <<<"$string_star")"
~$ echo "${array_star[@]}"
* 1 1 1 1 1 0 0 1
Двойное -цитирование необходимо (выше ), однако в качестве дополнительной меры Раку можно использовать для удаления всех *
путем добавления вызова, такого как .subst(...)
, (здесь заменяя ничем ). Работа -в коде выполнения -ниже (рассмотрите возможность применения того же подхода для удаления других специальных символов в bash
, таких как \
, [
и?
):
~$ read string_nostar <<< "$(raku -e slurp.subst\(「*」\).print <<<"$string_star")"
~$ read -a array_nostar <<< "$(raku -e slurp.comb.print <<<"$string_nostar")"
~$ echo "${array_nostar[@]}"
1 1 1 1 1 0 0 1