Как извлечь папки, разделить имена файлов по ключу и значению (s )и сохранить их в ассоциативном массиве?

Ответ @Olorins является правильным ответом на этот вопрос, но я хочу добавить дополнительную информацию , почему это не работает:


Вы можете использовать любой из этих:

rm "dir with spaces"
rm dir\ with\ spaces
dir="dir with spaces"; rm "$dir"

Но это не сработает:

dir="dir\ with\ spaces";
rm "$dir" # the backslash will be taken literally inside quotes 
rm $dir # this should work, shouldn't it? Please read below.

Последний вариант поначалу казался мне неинтуитивным. Но bash расширяет содержимое переменных, добавляя кавычки перед выполнением .

Вы можете использовать set -x, чтобы увидеть, что на самом деле выполняется:

( var="a\ b"; set -x; echo $var; )
+ echo 'a\' b
a\ b

Хотя вывод выглядит хорошо, пробел по-прежнему не экранирован, поскольку \заключен в одинарные кавычки.

1
29.05.2021, 15:25
1 ответ

У вас есть:

printf "%s\n" $FIND_RESULTS | sort | 
  while read -r line; do
   ...
    done
 
    echo "${!my_gems[@]}"

, где, независимо от отступа, echoнаходится вне конвейера. Bash по умолчанию запускает все части конвейера в подоболочках, поэтому назначения в цикле whileне видны после завершения конвейера. Shellcheck.net также предупреждает об этом :

.
Line 32:
        my_gems[$KEY]=$values
        ^-- SC2030: Modification of my_gems is local (to subshell caused by pipeline).

К сожалению, это не дает обходных путей.

В Bash вы можете либо включить опцию lastpipe, либо заменить канал подстановкой процесса:

shopt -s lastpipe
echo test | while read line; do
    out=$line
  done
echo "out=$out"

или

while read line; do
  out=$line
done < <(echo test)
echo "out=$out"

(lastpipe, вероятно, не сработает, если вы попробуете его в интерактивной оболочке, так как он привязан к управлению заданиями , а не .)

См.:Почему моя переменная локальна в одном цикле while read, но не в другом похожем цикле?


В любом случае это выглядит немного странно:

FIND_RESULTS=$(find...)

 printf "%s\n" $FIND_RESULTS 

findвыводит имена файлов, разделенные символами новой строки, что нормально, если вы знаете, что имена файлов не содержат их. Но здесь круговой обход -переменной и разделение слова из расширения без кавычек также разделяет любые имена файлов пробелами.

Вы можете просто запустить find... | while...напрямую. Или while...; done < <(find...).

Кроме того, обратите внимание, что вы почти всегда должны использовать while IFS= read -r line; do, чтобы предотвратить readот нарушения начальных и конечных пробелов. Ну, я надеюсь, что ваши имена файлов тоже не содержат их, но в любом случае.

Сейчас я не могу найти хороший справочный вопрос, но он касается IFSпробелов. Другие начальные и конечные разделители не удаляются с помощью readтолько для одного поля. Например. IFS=": " read -r foo <<< "::foobar "оставляет fooс буквальным ::foobar. Двоеточие сохранено, но конечные пробелы удалены.

3
28.07.2021, 11:28

Теги

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