Сценарий Linux bash для игнорирования символа ‘$’

Много раз я копировал и вставлял из руководства, в котором была следующая инструкция:

$ echo «Выполнить xyz»

и получил бы ошибку

$: команда не найдена

Итак, я создал сценарий bash, чтобы игнорировать «$» в начале; Решение такое:

  1. Поместите приведенный ниже сценарий в файл с именем ‘$’.
    • vim $
  2. Сделайте его исполняемым
    • chmod +x $
  3. Добавьте это в корзину
    • sudo cp $ /usr/bin/$

Сценарий:

#!/bin/bash
eval $@

4 ответа
4

Симпатичная идея. Но все не так просто.

Например, сравните выходы

echo 'a   b'

с

$ echo 'a   b'

(из-за разбиения слов).

Кроме того, он не работает с составными командами, такими как

for i in a b c ; do echo $i ; done

(потому что все после первого ; это другая команда).

Некоторые команды могут завершиться ошибкой в ​​зависимости от содержимого текущего каталога, например

$ [[ a = ? ]]

(если работает, попробуйте запустить touch 1 2 3).

  • О, я не думал об этом

    — Алекс Ангел

  • Обновлено еще несколько проблемных случаев.

    — болезнь

  • Чтобы решить первый случай, мы можем выполнить строку 1: #!/bin/bash Строка 2: "$@"

    — Алекс Ангел


Измените сценарий на просто "$@" и это должно работать для команд, отличных от встроенных команд оболочки. Показ сеанса с PS1='$ ':

$ cat '/ usr / bin / $' #! / usr / bin / env bash "$ @" $ $ echo 'ab' ab $ $ [[ a = b ]]/ usr / bin / $: строка 2: [[: command not found

Caveat: While this is a neat trick it encourages dangerous behaviour. Copying and pasting from sources which are not completely trusted is a big security risk (1, 2).

  • Some other commands from my reply still wouldn’t work.

    – choroba

  • It won’t work on builtins, no. But it’s as close as you’re ever going to get.

    – l0b0

While I understand why you’re trying to do what you do, but honestly, I’d really avoid masking something as critical as a sigil. Before you know it, you’ll end up doing something similar for # (as some commands out there assume you’re running them as root). That’s just going to be a mess.

What you could do instead, is write a script that processes (and if needed) trims whatever is in your clipboard. I’m going to assume you’re running some flavour of Linux for the purposes of simplicity. There are similar utilities for OSX, so if needed you can just modify the approach suggested here to fit your system.

Simple and risky

Apart from what you already have, install xclip, a command that allows you to interact with your system clipboard from the command line (e.g. xclip -selection c file.txt saves contents of file.txt to clipboard).

Now xclip can also print out (and as such access) whatever is in your clipboard by running xclip -o or xclip -out, so let’s start with that:

#!/usr/bin/env bash

str="$(xclip -o)"

Great, so now str contains whatever is in your system clipboard. Now if you’ve accidentally selected the leading $, chances are you’ve accidentally selected the space before it, or maybe even a line-break. To be safe, it’s probably best we trim the string in question. There’s ways to do this with bash’s many weird and wacky string manipulation constructs, but keeping it simple, we can just use xargs which, if no other arguments are provided, will trim the input string and return it as-is:

str="$(xclip -o | xargs)"

OK, so now we can check to see if the string in question starts with a $:

if [[ "${str:0:1}" == '$' ]];  затем str = "$ {str: 1}" fi

Итак, если первый символ нашей строки $, мы его отключаем и устанавливаем str быть равным str минус первый символ, избавившись от знака доллара. Вы можете добавить что-то вроде:

if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == "https://codereview.stackexchange.com/questions/257645/#" ]] ; then
    str="${str:1}"
fi

Чтобы учесть вышеупомянутую ведущую # символы, которые вы могли случайно скопировать. На этом этапе вы готовы делать то, что делаете сейчас:

## Either using eval:
eval $str
## or the shorter, but equally risky
$str

Сделайте скрипт исполняемым и назовите его как-нибудь коротко и по делу:

$ vim ~/bin/execpaste

#!/usr/bin/env bash

str="$(xclip -o | xargs)"
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == "https://codereview.stackexchange.com/questions/257645/#" ]]; then
    str="${str:1}"
fi

echo "Executing ${str}..."
$str

Сделайте скрипт исполняемым ($ chmod +x ~/bin/execpaste), и добавить ~/bin на свой путь (вместо того, чтобы добавлять скрипты непосредственно в /usr/bin), добавив это в свой .bashrc или же .profile файл:

export PATH="${PATH}:${HOME}/bin"

Чуть менее рискованно

Лично я предпочитаю иметь возможность видеть то, что я вставляю в свой терминал, перед его выполнением. На всякий случай … В таком случае я бы оставил первую часть сценария, но назову ее prepclip или что-то в этом роде (сокращение от подготовить буфер обмена). Большая его часть останется прежней, за исключением последней части (где команда фактически выполняется). Вместо этого я бы просто записал его обратно в буфер обмена:

#!/usr/bin/env bash

str="$(xclip -o | xargs)"
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == "https://codereview.stackexchange.com/questions/257645/#" ]]; then
    str="${str:1}"
fi

# send updated string to clipboard
echo "${str}" | xclip -selection c

С точки зрения фактического использования этого скрипта, действительно требуется 2 шага:

$ prepclip
$ <paste>

Но второй шаг для меня — это стоящая проверка на здравомыслие.

MacOS

Насколько мне известно, в MacOS есть 2 команды для вставки и копирования, которые вы можете использовать вместо них. Ниже представлена ​​версия последнего скрипта для MacOS (очистка ввода из буфера обмена и запись обратно в буфер обмена), на всякий случай, если вы используете MacOS:

#!/usr/bin/env bash

str="$(pbpaste | xargs)"
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == "https://codereview.stackexchange.com/questions/257645/#" ]]; then
    str="${str:1}"
fi

echo "${str}" | pbcopy

Это должно дать вам все, что вам нужно, без использования сигил.

Это немного неудобно, потому что тогда нужно не забыть пропустить все через CLIPBOARD выбор вместо более естественного PRIMARY один.

— Тоби Спейт

Есть очевидная ошибка, которую нужно исправить — помимо кавычек, $@ ведет себя как $*, значит, вы потеряли границы слов. То, что вы действительно хотели, было

#!/bin/sh
exec "$@"

Обратите внимание, что здесь уместна простая оболочка, так как вызывающая оболочка уже проделала все незаметные вещи с аргументами, например, разбиение слов и различные расширения. Ты уж точно не хотел eval!

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

Что, вероятно, сработает лучше, так это функция оболочки называется $.

  • Это все еще не удается с некоторыми примерами в моем ответе.

    — болезнь

  • Вы не можете создать функцию или псевдоним Bash с именем $.

    — l0b0

  • 1

    Похоже, ты можешь сделать alias "$"="" в zsh (проверено, на момент написания я использовал оболочку gnome)

    — Алекс Ангел

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

    — Тоби Спейт

  • @ l0b0, я думал, что это может быть невозможно с немодифицированным Bash, но не был достаточно уверен, что смогу это доказать, например, учитывая способы проникновения функций через среду. Конечно, если для кого-то это имеет значение, не составит труда изменить оболочку, чтобы она принимала $ как идентификатор функции. Я все равно не рекомендую!

    — Тоби Спейт

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *