Skip to main content
added 270 characters in body
Source Link
Lucas
  • 3k
  • 1
  • 18
  • 26

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)

EDIT

I just found this SO thread. It can be used to count the files like this

function count_files () {
  local name
  __count=0
  for name in *; do
    [[ -f "$name" ]] && ((__count++))
  done
  # like above ...
}

The speed is around 1:13 compared to the find version. That is manly because it starts less processes (the same reason the find version is faster than the ls version). The tread also has some other solutions with extglob. It all depends on the question if you want files or also links to files or whatnot. Again the code is faster but looks more complex now, so what kind of "simple" are you aiming at?

EDIT 2

Note although in the comments I said that the overhead to start a process might only be small compared to the overhead of sorting when you have to sort many files, for me it starts to show if I run the code in /usr/bin/ which has around 2500 files.

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)

EDIT

I just found this SO thread. It can be used to count the files like this

function count_files () {
  local name
  __count=0
  for name in *; do
    [[ -f "$name" ]] && ((__count++))
  done
  # like above ...
}

The speed is around 1:13 compared to the find version. That is manly because it starts less processes (the same reason the find version is faster than the ls version). The tread also has some other solutions with extglob. It all depends on the question if you want files or also links to files or whatnot. Again the code is faster but looks more complex now, so what kind of "simple" are you aiming at?

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)

EDIT

I just found this SO thread. It can be used to count the files like this

function count_files () {
  local name
  __count=0
  for name in *; do
    [[ -f "$name" ]] && ((__count++))
  done
  # like above ...
}

The speed is around 1:13 compared to the find version. That is manly because it starts less processes (the same reason the find version is faster than the ls version). The tread also has some other solutions with extglob. It all depends on the question if you want files or also links to files or whatnot. Again the code is faster but looks more complex now, so what kind of "simple" are you aiming at?

EDIT 2

Note although in the comments I said that the overhead to start a process might only be small compared to the overhead of sorting when you have to sort many files, for me it starts to show if I run the code in /usr/bin/ which has around 2500 files.

faster solution
Source Link
Lucas
  • 3k
  • 1
  • 18
  • 26

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)

EDIT

I just found this SO thread. It can be used to count the files like this

function count_files () {
  local name
  __count=0
  for name in *; do
    [[ -f "$name" ]] && ((__count++))
  done
  # like above ...
}

The speed is around 1:13 compared to the find version. That is manly because it starts less processes (the same reason the find version is faster than the ls version). The tread also has some other solutions with extglob. It all depends on the question if you want files or also links to files or whatnot. Again the code is faster but looks more complex now, so what kind of "simple" are you aiming at?

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)

EDIT

I just found this SO thread. It can be used to count the files like this

function count_files () {
  local name
  __count=0
  for name in *; do
    [[ -f "$name" ]] && ((__count++))
  done
  # like above ...
}

The speed is around 1:13 compared to the find version. That is manly because it starts less processes (the same reason the find version is faster than the ls version). The tread also has some other solutions with extglob. It all depends on the question if you want files or also links to files or whatnot. Again the code is faster but looks more complex now, so what kind of "simple" are you aiming at?

Source Link
Lucas
  • 3k
  • 1
  • 18
  • 26

First you can use a faster command to find the correct number. My tests show that find . -maxdepth 1 -type f -not -name '.*' | wc -l is faster than ls -l | grep '^-' | wc -l (about 4:3). If you also want hidden files you have to use ls -a or leave out the -not -name '.*' part with find.

Next you do not need to count the files twice but instead store the result in a variable and reuse it:

$(count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$count" -eq 1 ]]; then
    echo "1 file"
  else
    echo "$count files"
  fi)

As you can see you have to use one subshell, otherwise the variable will not be available for the second command. I also used the bash specific [[ ... ]] instead of [ ... ] here. In general it is the better solution.

Lastly you can also use the Bash variable $PROMPT_COMMAND to execute some code just before the $PS1 prompt is printed. That way you don't have to store all the code in the $PS1 variable. The $count variable will be global though. It could look like this:

function count_files () {
  __count=$(find . -maxdepth 1 -type f -not -name '.*' | wc -l)
  if [[ "$__count" -eq 1 ]]; then
    __plural=
  else
    __plural=s
  fi
}
PROMPT_COMMAND=count_files
PS1='other stuff $__count file$__plural more stuff'

Not sure which of these steps you would count as a simplification though :)