Почему не будет для цикла, выполняются на каталоге

Andreas прав это src/* расширен оболочкой. Однако, даже если Вы не указываете подстановочный знак cp мог бы все еще пропустить Ваши недавно созданные файлы, потому что будет состояние состязания между cp процесс, получающий доступ к каталогу и Вам (на самом деле, процесс, который создает файлы от Вашего имени), изменение каталога.

Что касается реализации CP GNU, это действительно получает список записей каталога перед фактическим копированием (см. copy_dir функционируйте здесь).

3
22.04.2013, 08:17
2 ответа

Ваш сценарий кодируется опасным способом.

Во-первых, я предполагаю, что Вы используете оболочку Bash, так как Вы отметили ее '/bash' и '/for'.

В моем ответе я заключу в кавычки этому замечательному руководству Bash, которое является, вероятно, лучшим источником для приобретения знаний Bash из там.

1) Никогда не используйте Замену Команды, ни одного вида, без кавычек. Здесь существует главная проблема: использование неупомянутого расширения для разделения вывода на аргументы.

Специфически говорящий, это $(find $DIRWORK -type d -name work) и $(find $DIR -type f) подвергнется Word Splitting, таким образом если find находит файл с пробелами на его имя, т.е. "имя файла", результат разделения слова Bash передаст 2 аргумента в пользу for команда для итерации, т.е. один для "файла" и один для "имени". В этом случае Вы хотите надеяться, что Вы получите "файл: Никакой такой файл или каталог" и "имя: Никакой такой файл или каталог", вместо того, чтобы потенциально нанести ущерб им, если они действительно существуют.

2) Условно, переменные среды (ПУТЬ, РЕДАКТОР, ОБОЛОЧКА...) и внутренние переменные оболочки (BASH_VERSION, СЛУЧАЙНЫЙ...), полностью использованы для своей выгоды. Все другие имена переменной должны быть нижним регистром. Так как имена переменной чувствительны к регистру, эта конвенция старается не случайно переопределять переменные окружения и внутренние переменные.

Ваши повреждения каталога $DIRWORK, что конвенция, и это также закрыло кавычки, таким образом если мы позволяем DIRWORK='/path/to/dir1 /path/to/dir2', find изучит два различных каталога, когда $DIRWORK закроется кавычки. Предмет использования кавычек очень важен в Bash, таким образом, Вы должны "Двойная кавычка" каждое расширение, а также что-либо, что могло возможно содержать специальный символ, например, "$var", "$", "$ {массив}", "$ (команда)". Bash рассматривает все в 'одинарных кавычках' как литерал. Изучите различие между 'и "и'. Посмотрите Кавычки, Аргументы, и Вы могли бы также хотеть смотреть на эту ссылку: http://wiki.bash-hackers.org/syntax/words

Это - более безопасная версия Вашего сценария, который я рекомендую Вам использовать вместо этого:

my_home="/root/mydir"

my_dir="$my_home/var"
dir_work="$my_home/Local"

while IFS= read -r -d '' f; do
    # I'm guessing that you also want to ignore stderr;
    # this is where the 2>&1 came from.
    if lsof -n "$f" | grep '[a-z]' > /dev/null 2>&1; then
        echo "hey, I'm safer now!"
    fi
done < <(find "$dir_work" -type f -print0)


while IFS= read -r -d '' f; do
    echo "2"
done < <(find "$dir_work" -type d -name 'work' -print0)

Как Вы видите, IFS переменная установлена быть emtpy, таким образом предотвратив read от обрезки продвижения и конечных пробелов от строки. read управляйте использует пустую строку ( -d '' ) как разделитель, для чтения, пока это не достигает \0. find потребности, которые будут изменены соответственно, поэтому это использует -print0 опция разграничить ее данные с \0 вместо новой строки - который, удивительно и злонамеренно, может быть часть имени файла. Разделение такого файла \n в две части взломает наш код.

Вы могли бы хотеть читать о Замене Процесса, если Вы не понимаете мой сценарий полностью.

Предыдущий ответ, который указал это find ... | while read name; do ...; done должен использоваться для чтения finds вывод может быть также плохим. while цикл выше выполняется в новой подоболочке с ее собственной копией переменных, скопированных с родителя. Эта копия затем используется, за что Вам нравится. Когда while цикл закончен, копия подоболочки отбрасывается, и исходные переменные родителя не изменились.

Если Вы нацеливаетесь при изменении некоторых переменных в этом while цикл и использует их впоследствии в родителе, рассматривает использование более безопасного сценария, выше которого предотвратит потерю данных.

5
27.01.2020, 21:13
  • 1
    "Никогда не использует Замену Команды, ни одного вида, без кавычек". Это просто придирается к мелочам, но это должно хорошо использовать замену команды без кавычек при установке переменной: something=$(basename "filename with spaces"). –   23.04.2013, 00:43

Этот код

for i in $(find $DIRWORK -type d -name work); do
    echo "2"
done

сначала выполнит эту строку

find $DIRWORK -type d -name work

ожидайте до find законченное выполнение и затем берет вывод и отложило его в for цикл

for i in the output of find; do
    echo "2"
done

только затем для цикла начнет выполняться.

Таким образом, если find занимает много времени для окончания for цикл должен ожидать долгое время, прежде чем он сможет запуститься.

Попытайтесь синхронизировать find команда в интерактивной подсказке

$ time find $DIRWORK -type d -name work

и посмотрите, сколько времени это берет.


Также примечание: Вы не должны использовать a for цикл к циклу по именам файлов. Используйте a while цикл с read как это:

find $DIRWORK -type d -name work | while read name; do
    echo "2"
done

Считайте это для получения дополнительной информации.

Премия: это выполняется while цикл параллельно к find. Это означает while цикл выполнит одно повторение как только find распечатывает одну строку. Это не должно ожидать find закончить выполняться.

2
27.01.2020, 21:13

Теги

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