How to solve a bash script argument with spaces

tumbleweed 20260219
linux v6.19.2-1-default x86_64

I am writing a script to show the usage of all of the files and directories starting in a specified directory using du.

The issue is providing all of the directories and files for input to du. If any of the names have spaces in the name, du does not parse the name correctly. The script is shown below.

dlst=$(/usr/bin/ls --quoting-style=shell-escape $basedir/)
txt="$cmd $dlst"
echo $txt
$txt

du is fed the list:
'du -sh '2025-07-15 16-51-37.mkv' '2025-07-15 16-52-43.mkv'
Note the single quotes. When run from the command line, there is no issue.

$ du -sh '2025-07-15 16-51-37.mkv' '2025-07-15 16-52-43.mkv'
7.0M	2025-07-15 16-51-37.mkv
420K	2025-07-15 16-52-43.mkv

When run from the script, here is the result:

$ du -sh '2025-07-15 16-51-37.mkv' '2025-07-15 16-52-43.mkv'
du: cannot access "'2025-07-15": No such file or directory
du: cannot access "16-51-37.mkv'": No such file or directory
du: cannot access "'2025-07-15": No such file or directory
du: cannot access "16-52-43.mkv'": No such file or directory

The single quotes are ignored and spaces are treated as an argument separator.

Is there a way to prevent the extra processing?

Here you go:

knurpht@Lenovo-P16:~/Movies> du -sh "The IT Crowd"/
28G     The IT Crowd/

Another one:

knurpht@Lenovo-P16:~/Movies> du -sh The\ IT\ Crowd/
28G     The IT Crowd/

I would appreciate if you would read the post first before responding. If I have been unclear, ask for clarification.

The problem is that there are two different command line interpretations, one directly as the examples you offered, and one issued in a shell script.

You may want to provide informations about your hidden script. Both your terminal output from bash and your script invoke the same command. The help you recieve depends on the information you provide.

I did. In the original post.

No, you did not.
You only said

But there is no script posted to see what exactly is there, nor as a start for others to re-create and experiment.
Thus, please post a minimal script that shows your problem.

They most probably are not, but are already interpreted by the script before the command itself is interpreted.

The original snippet slightly expanded:

#!/bin/bash

cmd="du -hs"
basedir="."
dlst="$(/usr/bin/ls --quoting-style=shell-escape $basedir/)"
txt="$cmd $dlst"
echo $txt
$txt

If executed with option -x

bash -x   t.sh 
+ cmd='du -hs'
+ basedir=.
++ /usr/bin/ls --quoting-style=shell-escape ./
+ dlst=''\''2025-07-15 16-51-37.mkv'\''
'\''2025-07-15 16-52-43.mkv'\''
t.sh'
+ txt='du -hs '\''2025-07-15 16-51-37.mkv'\''
'\''2025-07-15 16-52-43.mkv'\''
t.sh'
+ echo du -hs ''\''2025-07-15' '16-51-37.mkv'\''' ''\''2025-07-15' '16-52-43.mkv'\''' t.sh
du -hs '2025-07-15 16-51-37.mkv' '2025-07-15 16-52-43.mkv' t.sh
+ du -hs ''\''2025-07-15' '16-51-37.mkv'\''' ''\''2025-07-15' '16-52-43.mkv'\''' t.sh
du: Zugriff auf "'2025-07-15" nicht möglich: Datei oder Verzeichnis nicht gefunden
du: Zugriff auf "16-51-37.mkv'" nicht möglich: Datei oder Verzeichnis nicht gefunden
du: Zugriff auf "'2025-07-15" nicht möglich: Datei oder Verzeichnis nicht gefunden
du: Zugriff auf "16-52-43.mkv'" nicht möglich: Datei oder Verzeichnis nicht gefunden
4,0K    t.sh

you can see that the escapes are used and consumed in line

txt='du -hs '\''2025-07-15 16-51-37.mkv'\'' '\''2025-07-15 16-52-43.mkv'\'' t.sh'

as mentioned above. Even though I make the mistake myself from time to time, it’s never a good idea to use ls in a script. You could use an array instead

!/bin/bash

cmd="du -hs"
basedir="."

dlst=("$basedir"/*)
echo "$cmd ${dlst[@]}"
$cmd "${dlst[@]}"

This works but i would prefer a solution using find and xargs.

/t> bash t1.sh 
du -hs ./2025-07-15 16-51-37.mkv ./2025-07-15 16-52-43.mkv ./t1.sh ./t.sh
0       ./2025-07-15 16-51-37.mkv
0       ./2025-07-15 16-52-43.mkv
4,0K    ./t1.sh
4,0K    ./t.sh

@rawar find . -name '*.mkv' | xargs -I % du -sh % perhaps…

For the use with du i would recommend

find . -name '*.mkv'  -print0 |xargs -0  du -sh 

old-fashioned but better perfomance. This will start du only once instead of one start per line.

1 Like

Thank you. That gave me a clue to a solution.

# Get a list of files/directories for device usage
# Use xargs to preserve the escaping.
#
$basedir="$1"
dlst=$(/usr/bin/ls --quoting-style=shell-escape $basedir)
echo $dlst | xargs $cmd

When run on my home directory (basedir="~/"):

7.0M	2025-07-15 16-51-37.mkv
420K	2025-07-15 16-52-43.mkv
12K		argyllcms.cal
128K	arizona-county-map.jpg
4.2M	Audio
0		Audiobooks
...
53G		VirtualBox VMs
0		wallpaper

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.