cd into directory in while loop doesn't work - bash

I've the following script:
#!/bin/bash
ls -1 | while read d
do
[[ -f "$d" ]] && continue
echo $d
cd $d
done
Problem is that each cd says "[path]: No such file or directory", why?
Folder exists because I list it ...

I see two problems in your code:
You do not test for directories.
Once you cd in the dir, you stay there.
Please try this:
#!/bin/bash
ls -1 | while read d
do
test -d "$d" || continue
echo $d
(cd $d ; echo "In ${PWD}")
done

You shouldn't use ls like that.
#!/bin/bash
for d in */
do
[[ ! -d "$d" ]] && continue
echo "$d"
cd "$d"
# do something
cd "$OLDPWD"
done

Don't know what you are trying to achive.
Do you want to do some kind of recursive dic traversal ?
Here's ho I would do it:
#!/bin/bash
CWD="$(pwd)" #save starting directory
ls -1 | while read d
do
[[ ! -d "$d" ]] && continue
cd "$d"
echo "Changed to directory" $d
#Now you can do someting in the sub-directory
cd "$CWD" #Change back to old directory
done

The problem is you change the working directory in your script. This means that the second cd will be executed in the subdirectory you entered in the previous cd.
dir=`pwd`
ls -1 | while read d
do
[[ -f "$d" ]] && continue
cd "$dir"
echo $d
cd $d
#....
done

Related

How do I exclude some directories in a for loop?

I have created this loop but I want to exclude some directories from the job. I tried different ways but it keeps working on all directories. Can you please help me?
for d in */
do
cd $d
echo $d
cartel=$(echo ${d} | sed 's/\///')
echo $cartel
I tried with:
shopt -s extglob
for d in this_folder/!(global|plugins|css)/
do
...
done
You can test explicitely for the directory you want to skip:
you can compare $d to the directories you want to avoid and go to the next loop using continue when you don't want to process this directory :
for d in */ ; do
if [ "$d" == "global/" ] || [ "$d" == "plugins/" ] || [ "$d" == "css/" ] ; then
continue
fi
cd $d
echo $d
cartel=$(echo ${d} | sed 's/\///')
echo $cartel
cd ..
done

Bash Find Function Ubuntu - Find in directory tree, files that have the same name as their directory

I want to find and print files in directory tree, that have the sname name as theirs dirs.
This is my code so far:
#!bin/bash
if [ $# -eq 0 ]
then
echo "No args"
fi
if [[ -d $1 ]] #if its dir
then
find $1 -type f | (while read var1 #for every regular file in dir tree
do
if [[ -f $var1 ]]
then
echo $var1 #full path
# I dont know how to get the dir name
echo $(basename $var1) #file name
echo
#then compare it and print full path
fi
done)
fi
I want to do this using FIND function in bash linux. Thanks
You can use this script with find:
while IFS= read -rd '' f; do
d="${f%/*}"
[[ ${d##*/} == ${f##*/} ]] && echo "$f"
done < <(find . -type f -print0)

Why am I getting unbound variable i bash?

I have the following script which works for the most part till it hits a specific line:
#!/usr/bin/env bash
set -eux
# Go Home.
cd /vagrant/Freya/
CLEANED_ASSETS=false
## Clean up time!
## Remove all vendor and composer.lock folders - just because.
for f in *; do
if [[ -d $f ]]; then
if [[ $f != ".git" ]] && [[ $f != "bin" ]] && [[ $f != "docs" ]]; then
if [[ $f == "Loader" ]] && [[ $CLEANED_ASSETS == false ]]; then
cd "$f/"
if [[ -d "Assets" ]]; then
cd Assets/
rm -rf vendor composer.lock docs
let $CLEANED_ASSETS=true
cd ../../
fi
fi
cd "$f/"
rm -rf vendor composer.lock docs
cd ../
fi
fi
done
The issue is when it hits let $CLEANED_ASSETS=true I am not sure the proper way to set this variable to true, so it never enters this loop again. I keep getting:
+ let false=true
bin/clean-directories: line 21: true: unbound variable
CLEANED_ASSETS=true
No let, no $.
In particular, the let causes true to be treated as a variable name (searched for a numeric value), and referring to variable names that don't exist gets you flagged by set -u.

Sorting folders with bash

My root folder structure is like this:
My Family - Holiday
My Birthday[15.11]
Name-Name[1]
Name1
Name2
...
Now, I want every folder which contains a .info file to move to another directory.
Here's my code:
#!/bin/sh
for folder in *
do
echo $folder
if [ -e "$folder/*.info" ]
then
echo $folder
mv $folder ./Finished
fi
done
The echoes are only for testing.
I have found that every time a non-escaped character is in the name that the if is failing. How can I fix this?
Bash wants you to quote your variables.
#!/bin/bash
if [[ "$1" = "-v" ]]; then
Verbose=true
vopt="-v"
shift
else
Verbose=false
vopt=""
fi
for folder in *; do
$Verbose && printf "%s" "$folder"
if [[ -e "$folder/*.info" ]]; then
if mv "$vopt" "$folder" ./Finished/; then
$Verbose && echo -n " ... done"
fi
fi
$Verbose && echo ""
done
Note that it's a good idea to end your target directory with a slash. That way, if for some reason the Finished directory disappears, you'll get an error rather than silently renaming the first $folder to Finished, then moving all the other matches into the first match.
Note also that I'm using printf for some of the debugging output just in case one of your $folders starts with a hyphen.
UPDATE #1: you now have debugging controlled with the -v option.
UPDATE #2: I just realized that you are checking for the existence of *.info, literally. Note:
ghoti#pc ~$ mkdir foo
ghoti#pc ~$ touch foo/\*.info
ghoti#pc ~$ ls -la foo
total 0
-rw-r--r-- 1 ghoti ghoti 0 8 Aug 07:45 *.info
drwxr-xr-x 3 ghoti ghoti 102 8 Aug 07:45 .
drwx------+ 10 ghoti ghoti 340 8 Aug 07:44 ..
ghoti#pc ~$ [[ -e "foo/*.info" ]] && echo yes
yes
ghoti#pc ~$ mv foo/\*.info foo/bar.info
ghoti#pc ~$ [[ -e "foo/*.info" ]] && echo yes
ghoti#pc ~$
If what you really want to find is "any file ending in .info", then [[ -e is not the way to go. Pls confirm before I work more on this answer. :)
UPDATE #3:
Here's a version that finds moves your folder if the folder conains any .info file. Note that this does not grep the output of ls.
[ghoti#pc ~/tmp1]$ cat doit
#!/bin/bash
if [[ "$1" = "-v" ]]; then
Verbose=true
vopt="-v"
shift
else
Verbose=false
vopt=""
fi
for folder in *; do
infofile="$(
if [[ -d "$folder" ]]; then
cd "$folder"
for file in *.info; do
if [[ -f "$file" ]]; then
echo "$file"
break
fi
done
fi
)"
if [[ -f "$folder/$infofile" ]]; then
mv "$vopt" "$folder" ./Finished/
elif $Verbose; then
printf "%s ... skipped\n" "$folder"
fi
done
[ghoti#pc ~/tmp1]$ find . -print
.
./doit
./baz
./foo
./foo/bar.info
./Finished
[ghoti#pc ~/tmp1]$ ./doit -v
Finished ... skipped
baz ... skipped
doit ... skipped
foo -> ./Finished/foo
[ghoti#pc ~/tmp1]$
The primary issue is that you cannot use test -e *.info. You can parse the output of ls to check for the file. There are issues with parsing ls, but they are much less significant than many people make them out to be. If you do not allow newlines in filenames, the following should work:
#!/bin/sh
for dir in *; do
if ls -f "$dir" | grep -q '\.info$'; then
mv "$dir" ./Finished
fi
done
Do note that it is essential that no filenames have an embedded newline, since this will incorrectly identify a file named foo.info\nbar as if there were a single file named foo.info. In reality, this is unlikely to be a significant issue. If this is an issue, you will not want to use the shell for this, although you could do:
#!/bin/sh
for dir in *; do
for f in "$dir"/*; do
case "$f" in
*.info) mv "$dir" ./Finished; break;;
esac
done
done
Try this:
PATH_TO_FOLDER="/YOUR_FOLDER"
for f in `ls $PATH_TO_FOLDER`;
do
# Check filename
if [ $(echo $f | grep -Ec ".info$") -ne 1 ]
then
echo "We don't care"
else
## move the file
fi
done

How to find the deepest path that exists in Bash

When I get an error like:
$ ls /var/django-projects/daks/public/media/uploads/bandsaws/sneaks.jpg
ls: /var/django-projects/daks/public/media/uploads/bandsaws/sneaks.jpg: No such file or directory
I'd like to be able to ask what-is-the-deepest-path-that-does-exists and get back, say:
/var/django-projects/daks/public/media/
I think it could be done with a loop that added ../ on each iteration and quitted when a path that exists was found.
You may well find dirname useful. Something such as:
f=/var/django-projects/daks/public/media/uploads/bandsaws/sneaks.jpg
until [ -e "$f" ]; do f=$(dirname "$f"); done
echo $f
should give you /var/django-projects/daks/public/media/
Try:
FILE="/var/django-projects/daks/public/media/uploads/bandsaws/sneaks.jpg"
while true; do [ -e "$FILE" ] && break || FILE=$(dirname "$FILE"); done; echo $FILE
#!/bin/bash
function firstValidParent () {
d="$1"
[ -e "${d}" ] && echo $d || firstValidParent "${d%/*}"
}

Resources