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

xterm использует оболочку, хранящуюся в переменной $SHELL(, изначально установленную при входе в вашу оболочку входа ), для анализа командной строки. Итак, если вы хотите, чтобы командная строка анализировалась оболочкой zsh, просто выполните:

SHELL=/bin/zsh xterm -e 'echo $ZSH_VERSION; sleep 4'

Или просто:

xterm -e zsh -c 'echo $ZSH_VERSION; sleep 4'

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

1
09.06.2019, 01:20
3 ответа

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 ;}

Это почти правильно, но по-прежнему не работает, если имя файла начинается с символа -, потому что mvбудет рассматривать этот аргумент как опцию. Передайте --в mv, чтобы сказать ему «больше никаких опций после этой точки».Это очень распространенное соглашение, которое поддерживает большинство команд.

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]}}))
}
6
28.04.2021, 23:32

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

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

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

-2
28.04.2021, 23:32

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

3
28.04.2021, 23:32

Теги

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