If you're using bash, then you have two additional options. type f -name '*.mp3' -exec some command + For POSIX sh portability, use the -exec option:įind. When using find, be sure you use it properly. If you need recursion, the standard solution is find. Question: What happens if there are no *.mp3-files in the current directory? Then the for loop is executed once, with file="./*.mp3", which is not the expected behavior! The workaround is to test whether there is a matching file:Īnother solution is to use Bash's shopt -s nullglob feature, though this should only be done after reading the documentation and carefully considering the effect of this setting on all other globs in the script. *.mp3 pattern correctly expands to a separate word, and isn't subject to the effects of an unquoted expansion. Because globbing is the very last expansion step, each match of the. There is no need to interpret the results of an external utility. POSIX shells such as Bash have the globbing feature specifically for this purpose - to allow the shell to expand patterns into a list of matching filenames. Some command "$file" # …always double-quote expansions! ![]() If you don't need recursion, you can use a simple glob. There are several ways, primarily depending on whether you need a recursive expansion or not. Bash (or any other Bourne family shell) just doesn't work this way. This doesn't work! Especially if those lines are filenames. Filenames can also contain newlines.Īnother variation on this theme is abusing word splitting and a for loop to (incorrectly) read lines of a file. Nor can you simply change IFS to a newline. Instead of iterating over each file name, the loop will only execute once, assigning to f a string with all the filenames rammed together. This causes the entire output of ls to be treated as a single word. You can't simply double-quote the substitution either: In the ls examples, if the first filename starts with a hyphen, it may lead to pitfall #3. That may seem desirable since ls adds a newline, but if the last filename in the list ends with a newline, `…` or $() will remove that one also. The CommandSubstitution strips all trailing newline characters from its output. It's an external command whose output is intended specifically to be read by a human, not parsed by a script. Depending on which platform you're on, which arguments you used (or didn't use), and whether its standard output is pointing to a terminal or not, ls may randomly decide to replace certain characters in a filename with "?", or simply not print them at all. ![]() Pathnames may contain any character except NUL. If the command substitution returns multiple filenames, there is no way to tell where the first one ends and the second one begins. If ls produces any output containing a * character, the word containing it will become recognized as a pattern and substituted with a list of all filenames that match it. If a filename contains glob characters, it undergoes filename expansion (" globbing"). Assuming we have a file named 01 - Don't Eat the Yellow Snow.mp3 in the current directory, the for loop will iterate over each word in the resulting file name: 01, -, Don't, Eat, etc. If a filename contains whitespace (or any character in the current value of $IFS), it undergoes WordSplitting. You must use an entirely different approach. This entire approach is fatally flawed, and there is no trick that can make it work. Yes, it would be great if you could just treat the output of ls or find as a list of filenames and iterate over it. ![]() One of the most common mistakes BASH programmers make is to write a loop like this: grep foo bar | while read -r do ((count++)) done.
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |