Properly quote bash alias definition

烈酒焚心 提交于 2021-02-08 06:47:49

问题


I have the following command that I am trying to put into a bash alias. The command by itself works fine, but when I try to alias it, I am getting the following errors:

The Command

find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "$(find "{}" -type f | wc -l)" {}' \; | sort -nr

The Alias

alias csfiles='find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "$(find "{}" -type f | wc -l)" {}' \; | sort -nr'

The Error:

-sh: alias 0: not found
-sh: alias {} \; | sort nr: not found

I think this means I am not using quotes right but I am having trouble determining the correct combo. Help?


回答1:


Your outer find doesn't do anything you couldn't do with a simple glob. This eliminates a layer of quotes (along with the sh process for each directory found).

# Ignoring the issue of assuming no file name contains a newline
for d in ./*/; do
   echo "$(find "$d" -type f | wc -l) $d"
done

Just define a shell function to eliminate the second layer imposed on the argument to alias.

csfiles () {
  for d in ./*/; do
    echo "$(find "$d" -type f | wc -l) $d"
  done
}

The remaining call(s) to find can also be replaced with a for loop, eliminating the problematic assumption of one line per file name:

csfiles () {
  for d in ./*/; do
    echo "$(for f in "$d"/*; do [ -f "$f" ] && echo; done | wc -l) $d"
  done
}

You could keep find if it supports the -printf primary, because you don't care about the actual names of the files, just that you get exactly one line of output per file.

csfiles () {
  for d in ./*/; do
    echo "$(find "$d" -type f -printf . | wc -l) $d"
  done
}



回答2:


You can use double quotes around the definition, like this:

alias foo="find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo \"\$(find \"{}\" -type f | wc -l)\" {}' \; | sort -nr"

Every literal " inside the definition gets escaped: \".

Note: You also need to escape the inner command substitution to prevent it from getting expanded upon alias definition time. Like this ... \$(...)


As a follow up on chepners comment, you should pass the filename to the inner find command as an argument. Otherwise you will run into problems if one of your folders has a name with a " in it:

alias foo="find . -maxdepth 1 -mindepth 1 -type d -exec bash -c 'echo \"\$(find \"\${1}\" -type f | wc -l) \"\${1}\" \"' -- \"{}\" \; | sort -nr"


来源:https://stackoverflow.com/questions/53398792/properly-quote-bash-alias-definition

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!