mv: невозможно указать Нет такого файла или каталога в сценарии оболочки

16

Я написал скрипт для перемещения некоторых файлов из одной папки в другую, но я получил следующую ошибку, я проверил 2 папки и заметил, что для 1 папки есть такие файлы, а для другой нет таких файлов, но почему все они показывают "mv нет статистики Нет таких файлов или каталогов "

    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.42.17.124_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/195.113.161.13_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.199.61.205_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.51.218.235_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/213.73.40.105_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/41.225.7.4_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/83.230.127.122_tcp.folder/data/*': No such file or directory
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/
    129.88.70.226   132.187.230.1    138.96.116.22   155.185.54.250   192.38.109.144  193.136.227.163  193.175.135.61  195.113.161.13  83.230.127.122
    130.104.72.200  132.227.62.122   147.83.29.232   156.17.10.52     192.42.43.22    193.137.173.218  193.205.215.74  212.199.61.205
    131.130.69.164  132.252.152.194  148.81.140.193  157.181.175.249  192.43.193.71   193.144.21.131   193.226.19.30   212.51.218.235
    131.188.44.102  134.151.255.180  152.66.245.162  160.78.253.31    193.1.170.136   193.145.46.243   194.199.68.165  213.73.40.105
    131.254.208.10  138.48.3.203     152.81.47.4     192.114.4.3      193.136.166.56  193.166.160.98   194.42.17.124   41.225.7.4

скрипт такой:

    list=`ls dest_folder`
    cd dest_folder
    cwd=`pwd`
    for folder in $list;do
            mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
    done

Я запустил это в /home/esolve/project/capture/tcp_50x50/

misteryes
источник
1
Пожалуйста, покажите соответствующие части сценария.
Мат
Я обновил свой вопрос и добавил скрипт, спасибо!
Misteryes
Вам нужно добавить -rк mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAmateur
нет -rвыбора дляmv
мистериес

Ответы:

25
mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Кавычки ( ') не позволяют оболочке выполнять сглаживание. Команда *передается буквально mvкоманде, которая завершается ошибкой, поскольку не находит файлы, вызываемые *в указанных каталогах.

Измените это на:

mv "${cwd}/${folder}/data"/* "${cwd}/${folder}"

(Двойные кавычки для предотвращения проблем, если у вас когда-либо есть имя каталога с пробелами в нем. За *пределами кавычек.)

Вы все равно получите ошибки для пустых каталогов. (Такая же причина: если файл не находит соответствия для шаблона, он передает сам шаблон в качестве аргумента команде.)

Мат
источник
Двойные кавычки имеют смысл, но зачем мне ставить их *вне кавычек?
Sibbs Gambling
Если вы хотите, чтобы это было расширено, вам нужно это за пределами @SibbsGambling
Mat
8

Есть несколько проблем с вашим кодом:

list=`ls dest_folder`

Вы сохраняете вывод lsбез завершающих символов новой строки в $list. lsвыводит список имен файлов, разделенных символами новой строки. newlineявляется таким же допустимым символом, как и любой другой в имени файла, поэтому вывод не может быть надежно использован. Например, lsвыходные данные для каталога, который содержит aи bтакой же, как и для каталога, который содержит один файл с именем a<newline>b.

 cd dest_folder

Вы не проверяете провал этой команды. В общем, вам следует проверять состояние выхода команд, но это особенно верно cd, потому что остальные команды предполагают, что вы находитесь в этом новом каталоге, и это может иметь драматические последствия, если вы этого не сделаете.

cwd=`pwd`

Оболочки POSIX уже поддерживают (один) путь к текущему каталогу в $PWDпеременной, поэтому вам не нужно использовать его pwdздесь (особенно в общем случае, так как подстановка команд удаляет завершающие символы новой строки из пути). Кроме того, mvпринимает относительные пути, поэтому вам не нужно создавать абсолютный путь.

for folder in $list;do

Оставляя переменную без кавычек, это оператор split + glob в оболочках. То есть содержимое переменной разделяется (на разделители, упомянутые в $IFSспециальных правилах для пробельных символов), и каждый элемент, полученный в результате этого разделения, ищется с подстановочными знаками, чтобы их можно было развернуть в список подходящих файлов.

Здесь вам нужно разделение, но только для символов новой строки, и вы не хотите, чтобы сглаживание происходило, поэтому вам нужно отключить его:

 IFS='
 '; set -f
 for folder in $list
   mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Опять же, оставляя переменную без кавычек, это оператор split + glob . Здесь вы не хотите ни того, ни другого, поэтому вам нужно заключить эти переменные в кавычки.

Как уже упоминалось, подстановочные знаки расширяются только тогда, когда они не *заключены в кавычки, поэтому вам нужно убрать их из кавычек. Если вы ранее отключили глобализацию с помощью set -f, вам нужно будет восстановить ее set +fдо вызова этой команды.

Намного лучший способ написать это было бы:

cd dest_folder &&
  for folder in */;do
    mv -- "${folder}data/"* "$folder"
  done

Несколько заметок, хотя:

  • Это исключит скрытые папки и не будет перемещать скрытые файлы из dataпапок.
  • Мы не проверяем файлы, перезаписываемые в процессе (вы можете добавить эту -iопцию в mv).
  • Используя */, мы зацикливаемся только на каталогах , но это включает и символические ссылки на каталоги. Если вы не хотите, вам нужно добавить [ -L "${folder%/}" ] && continueвнутри цикла.
  • Если там нет скрытой папки, */она развернется сама по себе, поэтому вы получите сообщение об ошибке, в mvкотором говорится, что не удается найти файл с именем */data/*. Точно так же, если в любой из папок нет скрытого файла, вы получите сообщение об ошибке, that-folder/data/*которого не существует.
Стефан Шазелас
источник