Как я могу использовать подстановочные знаки стиля ms-dos с ls и mv?

9

У меня есть несчастье прийти из MS-DOS, но, по крайней мере, это заставляет меня понять, насколько мощнее Linux. Я работал над приведением Linux-Fu в нормальное состояние, но есть пара вещей, которые можно было бы сделать с DOS, но я не уверен, как лучше всего добиться этого с Linux:

Переименование нескольких файлов - с использованием двух подстановочных знаков

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\>rename *.txt *.bak

c:\> dir

Directory of c:\
    file1.bak
    file2.bak
    file3.bak
    file4.bak

Я знаю, что мог бы использовать find -execздесь, но возможно ли использовать более короткий синтаксис - возможно, mvс некоторыми специальными флагами или синтаксисом? Я предполагаю, что ключ к этому - второй * подстановочный знак, так как у linux не должно быть проблем с первым (т.е. я знаю, как выбрать файлы, которые я хочу переименовать, используя подстановочные знаки)

Переименование одного файла - с использованием одного подстановочного знака

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

Это было бы особенно полезно при переименовании длинных и громоздких имен файлов. Я подумал, что, возможно, я мог бы использовать mv file1.txt $1.bakв конечном итоге, file1.txt.bakчто также было бы приемлемо, но я не уверен, что вы можете ссылаться на $1параметр inline с помощью команды оболочки. Опять же, в этом конкретном случае просто удобно, как ms-dos убивает *подстановочный знак, который будет использоваться как своего рода совпадение захвата / замены для части имени файла.

Фильтрация списков каталогов с помощью подстановочного знака

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt
    text.txt
    \temp       (directory) 

c:\> dir file*

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\> t*

Directory of c:\
    text.txt
    \temp       (directory) 

Я не уверен, что правильный синтаксис для этого ls, или если это вообще возможно. Если я сделаю что-то подобное ls t*, я начну с каталогов t. Мой обходной путь либо использовал, find . --max-depth 1 -iname "t*"либо что-то в этом роде ls -al | grep t- ни один из них не такой короткий и простой, как dir t*есть.

Наконец, я знаю, что могу настроить псевдонимы, чтобы сделать эти длинные команды короче, но я хотел бы изучить некоторые из готовых linux-fu для этих вещей, потому что иногда вы подключены к удаленной системе или работаете на новой машине.

Так как же я могу mvи lsфайлы так же, как я dirи renameфайлы?

УХО
источник

Ответы:

15

Одно из фундаментальных отличий между cmdоболочками Windows и POSIX заключается в том, кто отвечает за подстановочные знаки. Оболочки выполняют все необходимые расширения перед запуском тех команд, которые вы запрашивали. cmd в основном передает шаблоны шаблонов командам без изменений. (Я говорю в основном, так как я думаю, что есть исключения, и переменные окружения расширяются в большинстве случаев.) Это делает написание a, renameкоторый будет работать с тем же синтаксисом, что и в cmdдовольно хитром.

Но есть renameдля Linux - с совершенно другими аргументами, посмотрите man-страницу (которая немного лаконична в моей системе и renameпоставляется из util-linuxпакета в моей системе, который должен быть широко доступен). Ваше первое переименование будет сделано так:

rename .txt .bak *.txt

Обратите внимание, что оболочка выполняет *расширение, поэтому renameсама думает, что она была вызвана так:

rename .txt .bak file1.txt file2.txt file3.txt ...

Таким образом, вы можете угадать одну версию файла:

rename .txt .bak file1.txt

Если вы не хотите использовать, renameно реализуете это сами, вы можете создать для этого функцию. Предполагая, что вы хотите изменить только расширение файла, и для переименования одного файла посмотрите на это:

$ function chext() {
  newext="$1"
  file="$2"
  newfile="${file%.*}$newext"
  echo mv "$file" "$newfile"
}
$ chext .csv test.txt
mv text.txt text.csv

$newfileсоздается с использованием удаления подстроки для удаления исходного расширения, а затем объединяет новое расширение. Вы можете расширить эту функцию для обработки нескольких файлов относительно легко.


Что касается вашего lsвопроса, используйте -dпереключатель. Это предотвратит lsперечисление содержимого каталогов.

Демо-версия:

$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:29 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.csv
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

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

$ rename .csv .txt f*
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Переименование одного файла

$ rename .txt .csv f1.txt 
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

По умолчанию ls

$ ls -l t*
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

test:
total 0
-rw-r--r-- 1 owner users 0 Jan  7 17:33 dont_show_me_please

ls это не проверяет каталоги

$ ls -ld t*
drwxr-xr-x 2 owner users 4096 Jan  7 17:33 test
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv
Мат
источник
очень хорошо! я думаю, что только что переместил пояс с моим linux-fu! Спасибо!
cwd
Совет, чтобы немного продвинуться в этом (и избежать ловушек): используйте простые функции или сценарии, чтобы увидеть, что происходит, когда вы делаете, somefunc *.Extесли этот шаблон не соответствует ни одному файлу, и поиграйтесь с цитированием, чтобы увидеть, удастся ли вам передать шаблон ( без его расширения) между функциями. Совет по безопасности: нигде не пользуйтесь rm, экспериментируя с расширением глобуса / оболочки :-)
Mat
4

Когда речь заходит о подстановочных знаках, имейте в виду, что они расширяются оболочкой. Приложение не знает, использовали ли вы подстановочные знаки или напечатали имена. Например, если вы печатаете rename *.txt *.bak, то renameкоманда видит что-то вроде rename file1.txt file2.txt existingfile.bak. Этого недостаточно для продолжения.

Я разберусь с вопросом о lsпервом, потому что это проще. Если вам нужны только совпадающие имена, то вам это не нужно ls, потому что оболочка уже выполняет расширение.

echo t*

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

ls -ld t*

Не существует стандартной утилиты для переименования файлов, потому что первые системы Unix не поставлялись с ней. Переносимый метод для переименования файлов использует цикл и немного многословен:

for x in *.txt; do mv -- "$x" "${x%.txt}.bak"; done

Существует несколько распространенных утилит для переименования файлов, ни одна из которых не гарантированно будет установлена ​​в данной системе Unix, но все они просты в установке. Вот основные из них:

  • renameиз util-linuxнабора, доступного в любой не встроенной системе Linux (и нигде больше). В Debian и его производных (включая Ubuntu) эта команда вызывается rename.ul. При условии, что не существует вхождения, .txtкроме окончательного расширения, вы можете написать

    rename .txt .bak *.txt
    
  • renameэто скрипт на Perl , который Debian и его производные , как корабль /usr/bin/rename. Вы можете переименовывать файлы в соответствии с произвольными командами Perl.

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmv, который может переименовывать, копировать и связывать файлы в соответствии с несколькими шаблонами, основанными на имени, и имеет много опций, касающихся того, что происходит, если целевое имя уже существует. Обратите внимание, что вы должны использовать кавычки для защиты символов подстановки от расширения оболочкой.

    mmv '*.txt' '#1.txt'
    
  • zmvявляется функцией zsh , доступной тогда и только тогда, когда вашей оболочкой является zsh. Он может соответствовать произвольным шаблонам zsh (поэтому вы можете сопоставлять имена файлов в соответствии с произвольными регулярными выражениями, а не только с подстановочными знаками, и вы можете сопоставлять файлы по другим критериям, таким как даты и размеры). zmvМожно также скопировать и ссылку.

    zmv '(*).txt' '$1.txt'
    

Если у вас есть некоторый контроль над машинами, которые вы используете, я рекомендую использовать zsh в качестве оболочки (она имеет другие преимущества по сравнению с bash) и поместить эти строки в ваш ~/.zshrc:

autoload -U zmv
alias zmv='noglob zmv -w'
alias zcp='zmv -C'
alias zln='zmv -L'
alias zsy='zmv -Ls'

noglobэто функция zsh, которая говорит оболочке не расширять символы подстановки в аргументе команды. Таким образом, вы можете написать zmv *.txt \$1.txt(вам всегда нужно защищать $текст замены).

Жиль "ТАК - перестань быть злым"
источник