Почему этот пакетный файл немедленно закрывается при вызове из ярлыка, несмотря на то, что он работает правильно при вызове из командной строки? - PullRequest
1 голос
/ 06 мая 2019

Редактировать 3 (РЕШЕНИЕ):

Как описано в его ответе michael_heath , проблема сводится к двум вещам: как именно Windows создает команды при выполнении чего-либочерез ярлык, и очень конкретные (и откровенно смешные) последствия включения \C cmd.exe.Для дальнейшего использования, если на этот вопрос StackOverflow возникнет какая-либо другая бедная душа, проблема была исправлена ​​путем изменения свойства «Цель» в ярлыке на слегка отредактированную версию ответа Майкла, в частности C:\Windows\System32\cmd.exe /C @"C:\{path-to-script}\link.bat". Вот еще и скриншот, , если необходимо, хотя, к сожалению, вы не видите всю строку цели.

Огромное спасибо еще раз Майклу.


Я пытаюсьчтобы создать персональную пакетную утилиту для создания символической ссылки на рабочем столе, почти так же, как «Отправить на ...> Рабочий стол» работает с ярлыками.Я часто использую символические ссылки, чтобы такие вещи, как мои файлы конфигурации bash (.bashrc и .bash_profile и т. Д.), Контролировались версиями в других местах для переносимости и для некоторых других вещей на моем компьютере.

Для простоты использования,Моя идея состояла в том, чтобы создать простой командный файл, чтобы сделать это для меня, и поместить символическую ссылку на рабочий стол.Затем я бы поместил ярлык для этого файла в папку «Отправить», чтобы он появлялся в «Отправить» в контекстном меню (я знаю, что для mklink требуются права администратора, поэтому ярлык также должен запускаться от имени администратора).

Вот файл, который я написал:

@echo off

set f=%~1
set switch=
if exist "%f%\*" set switch=/D

for /F "delims=" %%i in ("%f%") do set name=%%~nxi

mklink %switch% "%USERPROFILE%\Desktop\%name%" "%f%"
if not %ERRORLEVEL%==0 pause

Вот общее представление о том, что я пытаюсь сделать:

  1. Обрезать кавычки на входе, если есть (% ~ 1)
  2. Проверьте, является ли ввод каталогом
  3. Получите базовое имя и расширение файла ввода (%% ~ nxi)
  4. Makeссылка
  5. Если произошла ошибка, сделайте паузу, чтобы ее можно было увидеть, а не закрыть (потому что пакетный файл вызывается из ярлыка)

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

IЯ сделал несколько изменений, чтобы попытаться заставить его работать с файлами с пробелами, включая удаление кавычек на входе в этой первой строке, чтобы кавычки не удваивались позже, и что «delims =» в цикле for.Те два решения, которые я нашел здесь, на самом деле.

Но, несмотря на все мои усилия, независимо от того, что я делаю, файл немедленно закрывается, когда вводится пробел.Я набросал каждую строку с pause s, запускаю сценарий из командной строки с вводом вручную, чтобы он не выходил, и запускаю каждую отдельную команду (где это возможно) из командной строки.

УжасноКогда я запускаю его из командной строки или запускаю отдельные команды, все отлично работает даже с пробелами во входных данных.Я даже создал другой пакетный файл, который ничего не делает, кроме вывода ввода, который он получает, и запускает , что от Send To, и подтвердил, что ввод такой же, как я ввел из командной строки.

Что, черт возьми, идет не так, когда вызывается с этого ярлыка в Send To?


Edit 1: Свойства самого ярлыка следующие:

  • Цель: C: \ Users {имя пользователя} \ vc \ git \ util-scripts \ bat \ link.bat
  • Начать с: C: \ Users {имя пользователя} \ vc \ git \ util-scripts\ bat

Вот еще и скриншот:

Поскольку я только что сделал свой аккаунт, я не могу вставить изображение, но здесь оно


Редактировать 2: Это текущий код, который я использую, как предложил Герхард Барнард, однако проблема все еще сохраняется:

@echo off

set "fname=%~1"
set switch=
if exist "%fname%\.*" set "switch=/D"

for /F "delims=" %%i in ("%fname%") do (
    mklink %switch% "%USERPROFILE%\Desktop\%%~nxi" "%fname%"
    if errorlevel 1 pause
)

Ответы [ 2 ]

1 голос
/ 06 мая 2019

Попробуйте без опции /F, которая здесь не нужна, нам также не нужно устанавливать переменную, поскольку она будет прекрасно работать с расширенной мета-переменной:

@echo off
set "fname=%~1"
set switch=
if exist "%fname%\.*" set "switch=/D"

for %%i in ("%fname%") do (
    echo mklink %switch% "%USERPROFILE%\Desktop\%%~nxi" "%fname%"
    if errorlevel 1 pause
)
0 голосов
/ 07 мая 2019
@echo off
setlocal

rem Set the path for the created symlink.
set "linkdir=%USERPROFILE%\Desktop"

for %%A in (%*) do call :link "%%~A"

rem Check results.
echo: & dir /A:L "%linkdir%" & pause
exit /b

:link
set "switch="
if exist "%~1\*" set "switch=/D"
for /F "delims=" %%A in ("%~1") do set "name=%%~nxA"
if not defined name echo Variable "name" not defined.& exit /b 1
mklink %switch% "%linkdir%\%name%" "%~1"
exit /b 0

Ваш код пакетного файла работает.Этот код делает несколько файлов или папок.Этот код также помог сразу протестировать файлы, папки, файлы с символьными ссылками и папки с символическими ссылками в качестве целей.

Если вы хотите, чтобы обрабатывался только 1 объект, просто измените %* на "%~1".

Основной проблемой является командная строка в ярлыке.

C:\Users\{username}\vc\git\util-scripts\bat\link.bat

Тип файла .bat собирается создать команду, такую ​​как:

C:\Windows\System32\cmd.exe /C "C:\Users\{username}\vc\git\util-scripts\bat\link.bat" %*

%* заменяется переданными аргументами.

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

C:\Windows\System32\cmd.exe /C "C:\Users\{username}\vc\git\util-scripts\bat\link.bat" "C:\Users\a file.txt"

Строка команды после /Cимеет 4 двойные кавычки и двойные кавычки на обоих концах.Поведение изменяется из-за двойных кавычек.

Кавычка из cmd /?:

If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:

    1.  If all of the following conditions are met, then quote characters
        on the command line are preserved:

        - no /S switch
        - exactly two quote characters
        - no special characters between the two quote characters,
          where special is one of: &<>()@^|
        - there are one or more whitespace characters between the
          two quote characters
        - the string between the two quote characters is the name
          of an executable file.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

В разделе 1 «переключатель no / S» - истина, затем следующий - "ровно два символа кавычки" , что ложно.Теперь это применимо к разделу 2, в котором после /C можно сделать командную строку с зачеркнутыми двойными кавычками:

C:\Users\{username}\vc\git\util-scripts\bat\link.bat" "C:\Users\a file.txt

Пробел указан в кавычках, хотя остальная часть выставлена, что в данном случае является недопустимой командной строкой.Обратите внимание, что C:\Users\a file.txt является примером переданного аргумента, который был заключен в двойные кавычки как "C:\Users\a file.txt".

Изменение строки команды в ярлыке на:

C:\Windows\System32\cmd.exe /C echo: & "C:\Users\{username}\vc\git\util-scripts\bat\link.cmd"

Команда теперь C:\Windows\System32\cmd.exe, что дает больше контроля над командной строкой.После /C, echo: используется, чтобы избежать того, что командная строка начинается с двойных кавычек, что помогает предотвратить удаление двойных кавычек с обоих концов, поскольку командная строка больше не начинается с двойных кавычек.После & важна команда, которая теперь будет работать, даже если аргументы заканчиваются двойной кавычкой.

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

C:\Windows\System32\cmd.exe /C @"C:\Users\{username}\vc\git\util-scripts\bat\link.cmd"

Так что все, что лучше всего подходит для вашего варианта использования.

...