通过 shell 脚本转义字符串中的美元符号

假设我有一个名为 dd.sh 的脚本,我这样运行它

./dd.sh sample$name.mp4

所以 $1是字符串 sample$name.mp4

echo '$1' // shows $1


echo "$1" // shows "sample.mp4"; want "sample$name.mp4"

然后如何处理 $1,我可以检测是否有一个美元符号参数 $1

我想处理字符串到 sample\$name.mp4,或者只是检测参数 $filename中是否有美元符号

138610 次浏览

As you know, a dollar sign marks a variable. You have to take it into account when you are typing it.

You can escape the dollar

./dd.sh "sample\$name.mp4"

or just type it with single quotes

./dd.sh 'sample$name.mp4'

To check if there is a dollar sign in a variable, do

[[ $variable == *\$* ]] && echo 'I HAZ A DOLAR!!!' || echo 'MEH'

Your issue is not with the echo but with the assignment to $filename.

You say

filename="sample$name.mp4"

This will interpolate the string, which means expanding the variable $name. This will result in $filename having the value sample.mp4 (since $name is presumably undefined, which means it expands to an empty string)

Instead, use single quotes in the assignment:

filename='sample$name.mp4'

echo "$filename" will now result in the expected sample$name.mp4. Obviously, echo '$filename' will still just print $filename because of the single quotes.

If your question is:

Then how to process $1 that I can detect whether there is a dollar sign in parameter $1

You can try this:

if [[ $1 == *'$'* ]]
then
echo '$ was found'
else
echo '$ was not found'
fi

Output:

$ ./dd.sh 'sample$name.mp4'  // prints $ was found
$ ./dd.sh 'samplename.mp4'  // prints $ was not found

For example you have .env file with variables and password for postgres DB. As you know password should be urlencoded course % sing in password. So we have a problem here. Because BASH ignore $ and we get always wrong password for encode.

.env file



DB_NAME=sone_db
DB_PASS=A1$Bb%!Y$  # with dollar signs
...


bash script



#!/bin/bash
PSQL_COMMAND="DROP schema public CASCADE;"
PSQL_COMMAND+="CREATE schema public;"


set -o allexport
# set source file and get access to all variables in .env
source /path/.env


ENCODED_PASS=$(python -c "from urllib.parse import quote; print(quote('$DB_PASS'))");
psql postgres://$DB_USER:$ENCODED_PASS@$DB_HOST:5432/$DB_NAME -c "$PSQL_COMMAND"


echo $DB_PASS   # returns A1%!Y$
echo '$DB_PASS' # returns $DB_PASS
echo "$DB_PASS" # returns A1%!Y$


# disables variables
set +o allexport


# Wont work because BASH find $ sing in string and think that is variable,
so in first and last echo missed part $Bb%


To resolve this you need in .env file escape string in single quote



...
DB_PASS='A1$Bb%!Y$'
...


One option:

# Replace occurrences of $ with \$ to prevent variable substitution:
filename="${filename//$/\\$}"

I just realized my prompt was showing foo rather than foo$bar$baz as the name of the current branch. foo$bar$baz was getting assigned to PS1 and $bar and $baz were then expanded. Escaping the dollar signs before including the branch name in PS1 prevents unwanted expansions.

Demo:

Evidently, the single quotes ' results in no interpolation of enclosing characters.

cat > test.sh
echo '$1'
echo "$1"


% ./test.sh hello
$1
hello


% ./test.sh hello$world
$1
hello


% ./test.sh hello\$world
$1
hello$world      << Looks as expected


% ./test.sh 'hello\$world'
$1
hello\$world


% ./test.sh "hello\$world"
$1
hello$world      << Looks as expected