How to distinguish between files and directories using ssh2 on a remote server - file

We are attempting to move only the files from a remote server and putting the files directories into our database, so we need to be able to distinguish between a file and a directory. We have successfully been able to connect via SSH2 and we are able to read and display the files and directories within the remote path top directory. However, we have not been able to locate a php script that will allow us to find whether the returned name is a directory or a file. Below are a few examples we have tried. Any help is greatly appreciated and we thank you in advance.
$connection = ssh2_connect('www.myremote.com', 22);
ssh2_auth_password($connection, 'user', 'pw');
$sftp = ssh2_sftp($connection);
// THIS WORKS NICELY TO DISPLAY NAME FROM REMOTE SERVER
$handle = opendir("ssh2.sftp://$sftp/remotepath/");
echo "Directory handle: $handle<br>";
echo "Entries:<br>";
while (false != ($entry = readdir($handle))){
echo "$entry<br>";
}
// ONE OPTION THAT DOES NOT WORK
$handle = opendir("ssh2.sftp://$sftp/remotepath/");
echo "<br><br>2Directory handle: $handle<br>";
echo "4Entries:<br>";
while (false != ($entry = readdir($handle))){
if (is_dir(readdir($handel.''.$entry) ) ) {echo "<strong>$entry</strong><br>"; } else {
echo "$entry<br>"; //}
}
// ANOTHER OPTION THAT RETURNS AN EMPTY RESULT
$files = scandir('ssh2.sftp://'.$sftp.'/remotepath/');
foreach ($files as $file):
if (is_dir('ssh2.sftp://'.$sftp.'/remotepath/'.$file) ) {"<strong>".$file."</strong><br>"; } else { $file.'<br>'; }
endforeach;

if you use the Linux command line find this will help:
this is how you find only files named blah:
find . -type f -name *blah*
this is how you find only directories named blah:
find . -type d -name *blah*
in this case you could to the following to find all files in the /tmp directory (without going into the subdirectories of /tmp (maxdepth 1)) named anything:
$connection->exec('find /tmp -maxdepth 1 -type f -name "*"');
EDIT:
Ok, so here's a bit more code. This will connect to a server and echo a list of all directories in your home directory and then all files in your home directory:
$connection = ssh2_connect($host, 22);
ssh2_auth_password($connection, $user, $pass);
$the_stream = ssh2_exec($connection, '/usr/bin/find ~ -maxdepth 1 -type d');
stream_set_blocking($the_stream, true);
$the_result = stream_get_contents($the_stream);
echo "Directories only: <br><pre>" . $the_result . "</pre>";
fclose($the_stream);
$the_stream = ssh2_exec($connection, '/usr/bin/find ~ -maxdepth 1 -type f');
stream_set_blocking($the_stream, true);
$the_result = stream_get_contents($the_stream);
echo "Files only: <br><pre>" . $the_result . "</pre>";
fclose($the_stream);
You should be able to parse $the_result into an array by splitting on newlines or some such and get just the files or just the directories. Remove the "-maxdepth 1" from the find and you'll recurse through all subdirectories.

Related

How to add a delay after getting the list before starting the loop in the shell script

Below script list, the files, change the permissions on the file and moving it to a different folder. Sometimes the script is moving the file before the contents fully generated.
Need to add a delay after getting the list before starting the loop. Is this possible? Please help how to achieve this scenario to implement.
Can we use the sleep command to achieve this?
Script to change the file permissions and move it to main folder
function starts here
function mv_purge_files
{
cd $SRC
if  [ "$?" = "0" ]; then
for c in $(/usr/bin/ls *)
do
echo "ext: changing file permission $c"
/usr/bin/chmod 775 $c
echo "ext: moving $c"
/usr/bin/mv $c $TGT/$c
done
else
echo "Error accessing folder " $SRC
fi
}
program starts here 
SRC=/temp/file.in
TGT=/tgt/purge
mv_purge_files

count files found by find function in a shell script and save them in an array

I would like to make a shell script that finds a specific file and then asks the user which file he wants. But when I for example use the find command
(find . -name 2D.py)
it finds two files:
./Desktop/2D.py
./libcpab-master/2D.py
save these into a file:
file=$(find . -name 2D.py)
and counts them:
echo "${#key[#]}"
I get that only one name. It should be 2 files.
Also when I save 'file' in a array, there is only one element.
Hope you can help.
You have to define the "file" variable as an array. Try this
> find . -name 2D.py
./Desktop/2D.py
./libcpab-master/2D.py
> set -A file
> file=$(find . -name 2D.py)
> echo "${file[*]}"
./Desktop/2D.py
./libcpab-master/2D.py
> echo "${file[*]}" > file_list
> cat file_list
./Desktop/2D.py
./libcpab-master/2D.py
> wc file_list
2 2 39 file_list
>

Array not reading all values

I'm trying to get this arrays to work, but it reads only the first folder.
SFA=(folder1 folder2)
and the code:
for folders in "${SFA[#]}"
do
echo /media/$SFA
done
But it only seems to iterate trough one folder (tv1) 2 times. I can't see anything wrong with the code...
You can do something like this:
declare SFA=(folder1 folder2)
for folders in "${SFA[#]}"; do echo /media/$folders; done
The Output will be as follows:
:~$
/media/folder1
/media/folder2
I found my own mistake...
The code looks like this now and works as intended.
FOLDERARRAY=(tv1 tv2)
### Check for FOLDERS in FOLDERARRAY
#
for FOLDERS in "${FOLDERARRAY[#]}"
do
# echo /media/$SFA
if [ ! -d /media/$FOLDERS ]; then
echo /media/$FOLDERS; status="Couldn't find /media/$FOLDERS"
# exit 0
else
echo "found folder: /media/$FOLDERS"
find /media/${FOLDERARRAY} -mtime -7 -type f -size +2048 -exec
basename {} \;| sort |uniq >> /tmp/v$DATE-weekly.txt;
fi

How to automatically download a specific file type from within a wildcard folder on an FTP server

I'm trying to set up a way to automatically download all .mkv files on an ftp server within a folder of which I won't know the whole name. The most I will know is The.Walking.Dead.* Where star represents what I don't know of the folder name. Currently I'm using WinSCP and the closest code I've gotten from here is
#echo off
"C:\Program Files (x86)\WinSCP\WinSCP.com" ^
/log="D:\Documents\WinSCP Log\WinSCP.log" /ini=nul ^
/command ^
"open "ftp://ivay.myseedbox.site/downloads/manual/" ^
get "/The.Walking.Dead.*/*.mkv" "E:\Torrents\TV Shows\The Walking Dead\Season 8\" ^
PAUSE
exit
set WINSCP_RESULT=%ERRORLEVEL%
if %WINSCP_RESULT% equ 0 (
echo Success
) else (
echo Error
)
exit /b %WINSCP_RESULT%
But this returns with an error of
< 2017-11-06 12:47:02.172 Script: No file matching 'The.Walking.Dead.*' found.
. 2017-11-06 12:47:02.172 Listing file "E:\Torrents\TV".
. 2017-11-06 12:47:02.172 Retrieving file information...
> 2017-11-06 12:47:02.172 PWD
< 2017-11-06 12:47:02.308 257 "/"
> 2017-11-06 12:47:02.308 CWD /downloads/manual/E:\Torrents\TV
< 2017-11-06 12:47:02.433 550 Failed to change directory.
> 2017-11-06 12:47:02.433 TYPE I
< 2017-11-06 12:47:02.557 200 Switching to Binary mode.
> 2017-11-06 12:47:02.557 SIZE /downloads/manual/E:\Torrents\TV
< 2017-11-06 12:47:02.681 550 Could not get file size.
. 2017-11-06 12:47:02.681 Could not retrieve file information
< 2017-11-06 12:47:02.681 Script: Can't get attributes of file 'E:\Torrents\TV'.
< 2017-11-06 12:47:02.681 Could not retrieve file information
< 2017-11-06 12:47:02.681 Could not get file size.
. 2017-11-06 12:47:02.681 Script: Failed
So what I can see is it's trying to take my folder directory and use it as a file path and also ignoring the space in my local directory and squishing the remote and local directories together. So any help would be appreciated as I have almost no idea what's going on here.
When selecting files to transfer, file mask can be used for the last component of the path only.
One thing you can do is:
get -filemask=*.mkv /The.Walking.Dead.* "E:\Torrents\TV Shows\The Walking Dead\Season 8\"
But this will re-create the matching folder (The.Walking.Dead.*) as a subfolder of the target local folder (Season 8).
If you want to download the files (*.mkv) directly to the target local folder (Season 8), you can make WinSCP "rename" the source folder to Season 8:
get -filemask=*.mkv /The.Walking.Dead.* "E:\Torrents\TV Shows\The Walking Dead\Season 8"
Note the absence of the trailing backslash in the target path. It makes WinSCP download the matching source folder (The.Walking.Dead.*) to the target local folder (The Walking Dead, not Season 8!) under a name Season 8. As Season 8 already exists, it won't do anything with it and will directly continue with downloading the contained files.
The previous works for your specific case. In more complex cases, you would need to find out the name of the folder before the download. While it is not impossible to implement this using a plain batch file, it would be very complicated.
In such case, I would suggest using PowerShell with use of WinSCP .NET assembly.
With it, the script (e.g. download.ps1) would be like:
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "ftp.example.com"
UserName = "username"
Password = "password"
}
Write-Host "Connecting..."
$session = New-Object WinSCP.Session
$session.SessionLogPath = "session.log"
$session.Open($sessionOptions)
$remotePath = "/"
$localPath = "C:\local\path"
$pattern = "The.Walking.Dead.*"
$twdFolder =
$session.ListDirectory($remotePath).Files |
Where-Object { $_.IsDirectory -and ($_.Name -like $pattern) } |
Select-Object -First 1
if ($twdFolder -eq $Null)
{
Write-Host "No folder matching '$pattern' found."
}
else
{
Write-Host "Found folder '$($twdFolder.Name)', downloading..."
$sourcePath = [WinSCP.RemotePath]::Combine($remotePath, $twdFolder.Name)
$sourcePath = [WinSCP.RemotePath]::Combine($sourcePath, "*")
$destPath = Join-Path $localPath "*"
$transferResult = $session.GetFiles($sourcePath, $destPath).Check()
}
Write-Host "Done"
Extract WinSCP automation package along with the script and run the script like:
powershell.exe -ExecutionPolicy Unrestricted -File download.ps1
I completely forgot I posted on here and ended up figuring out how to do it myself. So sorry for not replying to anyone. I really appreciate the time you took to help me I just completely forgot about it. May not be the most clean method but it works for me lol. I kinda would like to add a download progress bar but I feel like that would be really complicated. This is what I ended up using:
param (
$localPath = "E:\Torrents\TV Shows\The Walking Dead\Season 8\",
$remotePath = "/downloads/manual/The.Walking.Dead.*",
$fileName = "*"
)
# Deletes new episode folder just in case one exists
Remove-Item "E:\Torrents\TV Shows\The Walking Dead\Season 8\New Episode" -recurse -EA SilentlyContinue
#Tells the user that the files are being downloaded
cls
"Downloading The Walking Dead. This can take a while."
"Please do not close this window."
try
{
# Load WinSCP .NET assembly
Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "removed"
PortNumber = 21
UserName = "removed"
Password = "removed"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Download the file and throw on any error and deletes the files from the server
$session.GetFiles(
($remotePath + $fileName),
($localPath + $fileName))
$session.RemoveFiles("/downloads/manual/The.Walking.Dead.*")
}
finally
{
$session.Dispose()
}
# Renames the downloaded folder
Rename-Item "E:\Torrents\TV Shows\The Walking Dead\Season 8\The.Walking.Dead.*" "New Episode" -EA SilentlyContinue
# Deletes unnecesary files
Remove-Item "E:\Torrents\TV Shows\The Walking Dead\Season 8\New Episode\*" -exclude *.mkv -EA SilentlyContinue
# Moves video file to proper directory
Move-Item "E:\Torrents\TV Shows\The Walking Dead\Season 8\New Episode\*.mkv" "E:\Torrents\TV Shows\The Walking Dead\Season 8" -EA SilentlyContinue
# Deletes new episode folder to clean things up
Remove-Item "E:\Torrents\TV Shows\The Walking Dead\Season 8\New Episode" -recurse -EA SilentlyContinue
exit 0
}
catch [Exception]
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}

powershell copy disk excluding particular file types

I am working on a PowerShell 2 script that will read a CD-ROM or DVD disk and copy its contents - the caveat is that I need to check for certain file types and NOT copy anything over with that filetype. So far I have this working:
$user = read-host "Enter owner's username:"
$drv = read-host "Enter Optical Drive letter (no colons or slashes):"
$list = Import-Csv badtypes.csv
$badlist = #()
$Extns = #()
ForEach($xt in $list)
{
$Extns += "."_$xt.Extention
}
$filepath = $drv +":\"
$cnts = Get-ChildItem $filepath -r
ForEach($itm in $cnts)
{
if($itm.PSis.Container)
{
#write new folder name in user's temporary folder
}
else
{
CheckFile $itm
}
}
Function CheckFile($fl)
{
$fildextension = [System.IO.Path]::GetExtention($fl)
$badfound = 0
ForEach($a in $Extns)
{
if($a -eq $fildextension)
{
$badfound = 1
}
}
if(badfound -eq 0)
{
write-host "File Type Acceptable:" $fl
# write file to proper place in the user's temporary folder
}
}
I'm having a problem getting the an empty folder created in the proper place and copying the (acceptable) file to the proper place.
Any help would be appreciated!
Sticking with a powershell solution, try this on for size:
$user = read-host "Enter owner's username:"
$drv = read-host "Enter Optical Drive letter (no colons or slashes):"
$list = Import-Csv badtypes.csv
$Exclusions = "*.$($list.Extension -join ",*.")"
$DestFolder = New-Item -path "\\BAAC\homedir\$user\transfer\$(get-date -f MMddyyyy.HH.mm)" -ItemType Directory
$FilePath = $drv +":\"
Write-Host "Copying files from $FilePath to $DestFolder`:"
Copy-Item "$FilePath*" -Destination $DestFolder -Exclude $Exclusions -Recurse -PassThru
explorer $DestFolder
Don't really need the user's name, but I left it in there. Here's what the script will do:
It gets the drive letter
Imports the list of extensions to exclude, builds a string from them (resultant string would be something like "*.bat,*.exe,*.com" if your CSV had 3 entries being bat, exe, and com).
It creates a date/time formatted folder in the desired folder
Then it recursively copies files and folders to new folder excluding anything on the exclusion list.
Lastly it opens up a Windows Explorer window to the destination folder that was created containing all the recently copied files and folders.
Edit: Updated to use the path specified in the comment. If this answer provided a solution to your question please mark it as the selected answer so future users can find it and use it without having to repeat questions.

Resources