Почему функция перемещения/копирования файлов перемещает только один файл за раз при использовании подстановочного знака «*»?

Почему функция перемещения/копирования файлов перемещает только один файл за раз при использовании подстановочного знака «*»?
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png

Он перемещает только первый .pngнайденный файл, а не все.

Как сделать так, чтобы команда применялась ко всем файлам, соответствующим подстановочным знакам?

решение1

mv1 *.pngсначала расширяет шаблон подстановочных знаков *.pngдо списка соответствующих имен файлов, затем передает этот список имен файлов в функцию.

Затем, внутри функции $1означает: взять первый аргумент функции, разбить его там, где он содержит пробелы, и заменить любые разделенные пробелами части, которые содержат подстановочные знаки и соответствуют хотя бы одному имени файла, списком соответствующих имен файлов. Звучит сложно? Это так, и такое поведение полезно только иногда и часто является проблематичным. Такое поведение разделения и сопоставления происходит только если $1происходит за пределами двойных кавычек, поэтому исправить это просто: использовать двойные кавычки.Всегда заключайте подстановки переменных в двойные кавычки.если только у вас нет веской причины не делать этого.

Например, если текущий каталог содержит два файла A* algorithm.pngи graph1.png, то mv1 *.pngпередается A* algorithm.pngв качестве первого аргумента функции, а graph1.pngв качестве второго аргумента. Затем $1разделяется на A*и algorithm.png. Шаблон A*соответствует A* algorithm.png, и algorithm.pngне содержит подстановочных знаков. Таким образом, функция в конечном итоге выполняется mvс аргументами -n, A* algorithm.png, algorithm.png, targetdirи -v. Если вы исправите функцию на

function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}

то он правильно переместит первый файл.

Обрабатыватьвсеаргументы, говорят оболочке обрабатывать все аргументы, а не только первый. Вы можете использовать "$@"для обозначения полного списка аргументов, переданных функции.

function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}

This is almost correct, but it still fails if a file name happens to begin with the character -, because mv will treat that argument as an option. Pass -- to mv to tell it “no more options after this point”. This is a very common convention that most commands support.

function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}

Оставшаяся проблема заключается в том, что в случае mvсбоя эта функция возвращает статус успешного выполнения, поскольку статус выхода команд в левой части конвейера игнорируется. В bash (или ksh) можно использовать , set -o pipefailчтобы заставить конвейер завершиться сбоем. Обратите внимание, что установка этого параметра может привести к сбою другого кода, работающего в той же оболочке, поэтому вам следует установить его локально в функции, что возможно с версии bash 4.4.

function mv1 {
  local -
  set -o pipefail
  mv -n -v -- "$@" "targetdir" | wc -l
}

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

function mv1 {
  mv -n -v -- "$@" "targetdir" | wc -l
  ((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}

решение2

$1— это первый аргумент функции, здесь первый файл, который соответствует *.png. Я думаю, это "$@"то, что вы хотите использовать вместо $1.

решение3

Вам придется использовать mv1 \*.png.

При взаимодействии с функциями Linux Terminal не передает звездочку напрямую команде, а выбирает первый соответствующий параметр и передает его команде.

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

Связанный контент