(Bash) Цикл for не работает должным образом

Линукс Торвальдс предлагает noatime.

Определения noatimeиnodiratime:

  • noatime : Without the "noatime" flag on your file system every read will cause a write, because the file system will update the access time. This is bad for the life-time of your SSD, since it supports a limited number of writes and this is causing significantly more writes.

Linux kernel developer Ingo Molnár claimed that it (atime) was “perhaps the most stupid Unix design idea of all times.” To disable the tracking of atime, the noatime option can be used to mount filesystems. For IO intensive tasks, the performance reward for turning off atime can be immediately apparent. But, turning off atime unconditionally will occasionally break certain software like mail tools that compare mtime and atime to determine whether there is unread mail or not. The tmpwatch utility and some backup tools also use atime and can misbehave if atime is incorrect. Audit requirements are another reason for keeping atime enabled.

  • nodiratime : This is the same as the noatime option but this only applies to directories. Note that turning on noatime implicitly means that nodiratime is enabled as well.
1
01.10.2019, 15:35
1 ответ

Ошибка, которую вы получаете, указывает, что $chunkсодержит многострочное значение, все числа от 0 до 9. Это произойдет, если слово -расщепление не произойдет в результате $(seq...)в for.

Обычный способ предотвратить разбиение слова -заключается в заключении расширения в двойные -кавычки, чтобы for chunk in "$(seq...)"не расширялось. Но здесь это не так, поскольку вы бы знали, добавили ли вы двойные -кавычки, и в любом случае это работает в некоторых случаях.

Но разбиение слова -не всегда одинаково, оно основано на значении IFS, которое по умолчанию содержит пробел, табуляцию и новую строку($' \t\n'с использованием стиля C -цитирования ). Если он содержит что-то другое, то эти символы будут приняты в качестве разделителей слов.

И действительно, вы модифицировали IFSвнутри select, непосредственно перед вызовомfoo:

local IFS=@
case "@${options[*]}@" in
(*"@$opt@"*)
        foo

Способ работы области видимости переменных в Bash заключается в том, что fooтакже видит измененное значение IFS. localне означает, что изменение видно только этой функции,но вместо этого он также виден для всех подфункций, вызываемых с этого уровня:

$ x=999
$ a() { echo "a: x=$x"; }
$ b() { local x=$1; a; }
$ b 123
a: x=123

Это не похоже на то, что было бы, скажем, в C.


В качестве обходного пути можно было бы вместо этого сохранить IFSв другую переменную, что-то вроде этого:

local oldifs=$IFS
IFS=@
str="@${options[*]}@"
IFS=$oldifs
case $str in...

или изменить его в подоболочке (, скрывая IFSизменение там):

str=$(IFS=@; echo "@${options[*]}@")
case $str in...

Вы также можете создать функцию для объединения строк (, скрывающую IFSизменение в функции ), вам просто нужны ссылки на имена для передачи переменных по имени:

# join a b c:
# join the values of array 'a' with the character 'b', and put the result in 'c'
join() {
    local -n _arr=$1
    local IFS=$2
    local -n _res=$3
    _res="${_arr[*]}"
}
src=(11 22 33)
join src @ dst
echo "$dst"        # outputs "11@22@33"

(Конечно, это немного громоздко для одного использования, и ссылки на имена тоже не идеальны :ссылка на имя внутри функция не может ссылаться на переменную с таким же именем снаружи это (по крайней мере в Bash 4 ). Небольшое преимущество этого по сравнению с просто использованием подстановки команд заключается в том, чтобы избежать форка для запуска подоболочки.)

Или, на всякий случай, (повторно )устанавливайте IFSкаждый раз, когда вам это нужно. Внутриfoo:

foo() {
    local IFS=$' \t\n'      # or just IFS=$'\n'
    for chunk in $(seq...); do
       ...
}
2
27.01.2020, 23:30

Теги

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